@unified-product-graph/core 0.8.2 → 0.8.5
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 +13 -0
- package/dist/index.cjs +69 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +86 -8
- package/dist/index.d.ts +86 -8
- package/dist/index.js +68 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [0.8.5] - 2026-06-02
|
|
11
|
+
|
|
12
|
+
Co-version with the @unified-product-graph/* 0.8.5 fast-follow (skill_audit source resolution, CLI/docs consistency, npx-cache fix, exercise-aware prioritise hint). No spec/catalogue change; `UPG_VERSION` stays `0.8.4`.
|
|
13
|
+
|
|
14
|
+
## [0.8.4] - 2026-06-02
|
|
15
|
+
|
|
16
|
+
Framework exercises. `UPG_VERSION` is now `0.8.4` (catalogue change). Folds the 0.8.3 patch train (CLI/MCP wiring fixes; no catalogue change).
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- `framework_exercise` entity type (Workspace domain): one run of a framework over a set of entities. Containment-free, with a draft/active/archived lifecycle and `framework_id` + `inputs_snapshot` properties.
|
|
20
|
+
- `framework_exercise_includes_node` edge (`includes` / `included_in`, polymorphic target): links an exercise to each entity it scores and carries the framework's per-entity result (a MoSCoW bucket, a RICE score, a canvas slot, a funnel stage) as edge properties.
|
|
21
|
+
- Gated edge properties: `UPGEdge.properties` plus a `carries_properties` capability flag on edge definitions. Only edges that opt in may carry a payload; the canonical serializer round-trips it byte-stably. New `edgeCarriesProperties(type)` helper.
|
|
22
|
+
|
|
10
23
|
## [0.8.2] - 2026-06-02
|
|
11
24
|
|
|
12
25
|
Co-version with the @unified-product-graph/* 0.8.2 release train.
|
package/dist/index.cjs
CHANGED
|
@@ -104,6 +104,7 @@ __export(index_exports, {
|
|
|
104
104
|
collectSlugsForType: () => collectSlugsForType,
|
|
105
105
|
compareVersions: () => compareVersions,
|
|
106
106
|
computeBodyChecksum: () => computeBodyChecksum,
|
|
107
|
+
edgeCarriesProperties: () => edgeCarriesProperties,
|
|
107
108
|
evaluateAntiPatterns: () => evaluateAntiPatterns,
|
|
108
109
|
findInvalidStatusMigrationTargets: () => findInvalidStatusMigrationTargets,
|
|
109
110
|
formatUpgText: () => formatUpgText,
|
|
@@ -676,8 +677,8 @@ var UPG_DOMAINS = [
|
|
|
676
677
|
{
|
|
677
678
|
id: "workspace",
|
|
678
679
|
label: "Workspace",
|
|
679
|
-
description: "Spatial thinking spaces for arranging entities, debating decisions, and committing to the graph. Workspaces are transient canvases that sit alongside all other domains, letting you compose and explore relationships before they become permanent graph structure.",
|
|
680
|
-
types: ["workspace"]
|
|
680
|
+
description: "Spatial thinking spaces for arranging entities, debating decisions, and committing to the graph. Workspaces are transient canvases that sit alongside all other domains, letting you compose and explore relationships before they become permanent graph structure. A framework exercise is a structured workspace: one run of a framework (MoSCoW, RICE, Kano, \u2026) applied to a chosen set of entities, with each entity's result recorded on the exercise-to-entity edge rather than the entity itself.",
|
|
681
|
+
types: ["workspace", "framework_exercise"]
|
|
681
682
|
}
|
|
682
683
|
];
|
|
683
684
|
var UPG_ENTITY_TO_DOMAIN = Object.freeze(
|
|
@@ -1103,7 +1104,8 @@ var UPG_ENTITY_META = [
|
|
|
1103
1104
|
{ name: "integration_partner", type_id: "ent_311", maturity: "stable", since: "0.1.0" },
|
|
1104
1105
|
{ name: "partner_revenue_share", type_id: "ent_312", maturity: "stable", since: "0.1.0" },
|
|
1105
1106
|
// ── Workspace ──
|
|
1106
|
-
{ name: "workspace", type_id: "ent_328", maturity: "proposed", since: "0.2.0" }
|
|
1107
|
+
{ name: "workspace", type_id: "ent_328", maturity: "proposed", since: "0.2.0" },
|
|
1108
|
+
{ name: "framework_exercise", type_id: "ent_350", maturity: "proposed", since: "0.8.4" }
|
|
1107
1109
|
];
|
|
1108
1110
|
var UPG_ENTITY_META_BY_NAME = new Map(
|
|
1109
1111
|
UPG_ENTITY_META.map((m) => [m.name, m])
|
|
@@ -2256,6 +2258,18 @@ var UPG_EDGE_CATALOG = {
|
|
|
2256
2258
|
// universal across the DDD type family. Verbs follow DDD literature:
|
|
2257
2259
|
// aggregate belongs_to context, context contains aggregates.
|
|
2258
2260
|
node_belongs_to_bounded_context: { forward_verb: "belongs_to", reverse_verb: "contains", classification: "cross-domain", source_type: "node", target_type: "bounded_context" },
|
|
2261
|
+
// ── Cross-domain: Framework exercises ────────────────────────────────────────
|
|
2262
|
+
// A framework_exercise is one run of a framework (MoSCoW, RICE, Kano, …) over a
|
|
2263
|
+
// set of entities. It `includes` each entity it touches; the framework's
|
|
2264
|
+
// per-entity result — a MoSCoW bucket, a RICE score, a canvas slot, a funnel
|
|
2265
|
+
// stage — rides on this edge's `properties`, NOT on the entity node. A value
|
|
2266
|
+
// that exists only within a specific exercise is a fact about the relationship,
|
|
2267
|
+
// not the entity, so it lives on the edge (same principle as owner-as-edge).
|
|
2268
|
+
// Polymorphic (`target_type: 'node'`): an exercise can include any entity type,
|
|
2269
|
+
// which closes the feature-only limitation structurally. `carries_properties`
|
|
2270
|
+
// opts this edge into the gated edge-property model. See ADR
|
|
2271
|
+
// 2026-06-02-framework-exercises.
|
|
2272
|
+
framework_exercise_includes_node: { forward_verb: "includes", reverse_verb: "included_in", classification: "cross-domain", source_type: "framework_exercise", target_type: "node", carries_properties: true },
|
|
2259
2273
|
// ── New edges replacing deleted string properties ────────────────────
|
|
2260
2274
|
// Marketing
|
|
2261
2275
|
marketing_strategy_pursues_outcome: { forward_verb: "pursues", reverse_verb: "pursued_by", classification: "cross-domain", source_type: "marketing_strategy", target_type: "outcome" },
|
|
@@ -2885,7 +2899,9 @@ var UPG_POLYMORPHIC_EDGE_KEYS = [
|
|
|
2885
2899
|
"node_owned_by_department",
|
|
2886
2900
|
"node_owned_by_person",
|
|
2887
2901
|
// Universal architecture references
|
|
2888
|
-
"node_belongs_to_bounded_context"
|
|
2902
|
+
"node_belongs_to_bounded_context",
|
|
2903
|
+
// Framework exercises (an exercise can include any entity type)
|
|
2904
|
+
"framework_exercise_includes_node"
|
|
2889
2905
|
];
|
|
2890
2906
|
var _POLY_KEY_SET = new Set(UPG_POLYMORPHIC_EDGE_KEYS);
|
|
2891
2907
|
function isPolymorphicEdge(key) {
|
|
@@ -2895,6 +2911,10 @@ function isPolymorphicEdge(key) {
|
|
|
2895
2911
|
function isRegisteredPolymorphicEdge(key) {
|
|
2896
2912
|
return _POLY_KEY_SET.has(key);
|
|
2897
2913
|
}
|
|
2914
|
+
function edgeCarriesProperties(type) {
|
|
2915
|
+
const def = UPG_EDGE_CATALOG[type];
|
|
2916
|
+
return def?.carries_properties === true;
|
|
2917
|
+
}
|
|
2898
2918
|
|
|
2899
2919
|
// src/catalog/legacy-product-stages.ts
|
|
2900
2920
|
var LEGACY_PRODUCT_STAGES = Object.freeze({
|
|
@@ -3546,7 +3566,13 @@ function canBeChildOf(childType, parentType) {
|
|
|
3546
3566
|
return getValidChildren(parentType).includes(childType);
|
|
3547
3567
|
}
|
|
3548
3568
|
var UPG_CONTAINMENT_FREE_TYPES = /* @__PURE__ */ new Set([
|
|
3549
|
-
"person"
|
|
3569
|
+
"person",
|
|
3570
|
+
// A framework_exercise has no structural parent: it anchors to the entities
|
|
3571
|
+
// it scores via the `framework_exercise_includes_node` edge, not by
|
|
3572
|
+
// containment. Modelling it as a product child would force a containment edge
|
|
3573
|
+
// and read against the whole point of the exercise model (relational, not
|
|
3574
|
+
// hierarchical). Same posture as `person`. See ADR 2026-06-02-framework-exercises.
|
|
3575
|
+
"framework_exercise"
|
|
3550
3576
|
]);
|
|
3551
3577
|
function isContainmentFreeType(entityType) {
|
|
3552
3578
|
return UPG_CONTAINMENT_FREE_TYPES.has(entityType);
|
|
@@ -5848,6 +5874,31 @@ var TEMPLATE_LIFECYCLES = [
|
|
|
5848
5874
|
// ── Phase B: SALES_DEAL (qualified → proposal → negotiation → won/lost) ─────
|
|
5849
5875
|
fromTemplate("deal", SALES_DEAL_TEMPLATE)
|
|
5850
5876
|
];
|
|
5877
|
+
var FRAMEWORK_EXERCISE_LIFECYCLE = {
|
|
5878
|
+
entity_type: "framework_exercise",
|
|
5879
|
+
initial_phase: "draft",
|
|
5880
|
+
terminal_phases: ["archived"],
|
|
5881
|
+
phases: [
|
|
5882
|
+
{
|
|
5883
|
+
id: "draft",
|
|
5884
|
+
label: "Draft",
|
|
5885
|
+
description: "The exercise has been created and entities pulled into scope, but the framework's inputs have not all been filled in yet.",
|
|
5886
|
+
transitions_to: ["active", "archived"]
|
|
5887
|
+
},
|
|
5888
|
+
{
|
|
5889
|
+
id: "active",
|
|
5890
|
+
label: "Active",
|
|
5891
|
+
description: "The current, authoritative run of its framework. Its include edges carry the live results consumers read, rank, and render by.",
|
|
5892
|
+
transitions_to: ["archived"]
|
|
5893
|
+
},
|
|
5894
|
+
{
|
|
5895
|
+
id: "archived",
|
|
5896
|
+
label: "Archived",
|
|
5897
|
+
description: "A past run, retained for provenance. Still queryable but superseded by a newer exercise and hidden from default views. Can be revived to active.",
|
|
5898
|
+
transitions_to: ["active"]
|
|
5899
|
+
}
|
|
5900
|
+
]
|
|
5901
|
+
};
|
|
5851
5902
|
var UPG_LIFECYCLES = [
|
|
5852
5903
|
// Product (root)
|
|
5853
5904
|
PRODUCT_LIFECYCLE,
|
|
@@ -5949,6 +6000,8 @@ var UPG_LIFECYCLES = [
|
|
|
5949
6000
|
// Product & Growth
|
|
5950
6001
|
VARIANT_LIFECYCLE,
|
|
5951
6002
|
GROWTH_CAMPAIGN_LIFECYCLE,
|
|
6003
|
+
// Workspace
|
|
6004
|
+
FRAMEWORK_EXERCISE_LIFECYCLE,
|
|
5952
6005
|
// ── Template-generated lifecycles ─────────────────────────────────
|
|
5953
6006
|
...TEMPLATE_LIFECYCLES
|
|
5954
6007
|
];
|
|
@@ -10138,6 +10191,11 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
10138
10191
|
},
|
|
10139
10192
|
methodology: { type: "string", description: "Forecasting methodology used" }
|
|
10140
10193
|
},
|
|
10194
|
+
// FrameworkExerciseProperties: Framework exercise: one run of a framework over a set of entities.
|
|
10195
|
+
framework_exercise: {
|
|
10196
|
+
framework_id: { type: "string", description: "Which framework this exercise runs: a framework id (e.g. 'moscow', 'rice-scoring', 'kano-model'). Resolves against the framework catalog." },
|
|
10197
|
+
inputs_snapshot: { type: "object", description: "Optional frozen copy of the framework's input spec at apply time, so a historical exercise still renders correctly if the framework definition later evolves (inputs added, removed, or rescaled)." }
|
|
10198
|
+
},
|
|
10141
10199
|
// FunnelProperties: Funnel entity.
|
|
10142
10200
|
funnel: {
|
|
10143
10201
|
funnel_type: { type: "string", enum: ["acquisition", "activation", "retention", "revenue", "referral", "custom"], description: "Which stage of the customer lifecycle this funnel measures" },
|
|
@@ -19756,7 +19814,7 @@ var PORTFOLIO_GUIDE = {
|
|
|
19756
19814
|
var WORKSPACE_GUIDE = {
|
|
19757
19815
|
domain_id: "workspace",
|
|
19758
19816
|
anchor_entity: "workspace",
|
|
19759
|
-
creation_sequence: ["workspace"],
|
|
19817
|
+
creation_sequence: ["workspace", "framework_exercise"],
|
|
19760
19818
|
patterns: [],
|
|
19761
19819
|
required_bridges: [],
|
|
19762
19820
|
anti_patterns: [
|
|
@@ -24764,7 +24822,7 @@ var NODE_KEY_ORDER = [
|
|
|
24764
24822
|
"sort_order",
|
|
24765
24823
|
"properties"
|
|
24766
24824
|
];
|
|
24767
|
-
var EDGE_KEY_ORDER = ["id", "source", "target", "type", "mapping_confidence"];
|
|
24825
|
+
var EDGE_KEY_ORDER = ["id", "source", "target", "type", "mapping_confidence", "properties"];
|
|
24768
24826
|
var CROSS_EDGE_KEY_ORDER = ["id", "source", "target", "type", "source_product_id", "target_product_id", "mapping_confidence"];
|
|
24769
24827
|
var PRODUCT_KEY_ORDER = ["id", "title", "description", "stage", "properties"];
|
|
24770
24828
|
function canonicalNode(node) {
|
|
@@ -24776,7 +24834,8 @@ function canonicalNode(node) {
|
|
|
24776
24834
|
}
|
|
24777
24835
|
function canonicalEdge(edge) {
|
|
24778
24836
|
return orderedObject(edge, EDGE_KEY_ORDER, {
|
|
24779
|
-
forceKeys: ["id", "source", "target", "type"]
|
|
24837
|
+
forceKeys: ["id", "source", "target", "type"],
|
|
24838
|
+
openKeys: ["properties"]
|
|
24780
24839
|
});
|
|
24781
24840
|
}
|
|
24782
24841
|
function canonicalCrossEdge(edge) {
|
|
@@ -24930,7 +24989,7 @@ function isCanonical(text) {
|
|
|
24930
24989
|
}
|
|
24931
24990
|
|
|
24932
24991
|
// src/index.ts
|
|
24933
|
-
var UPG_VERSION = "0.8.
|
|
24992
|
+
var UPG_VERSION = "0.8.4";
|
|
24934
24993
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
24935
24994
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
24936
24995
|
var UPG_TYPES = getTypes();
|
|
@@ -25079,6 +25138,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
25079
25138
|
collectSlugsForType,
|
|
25080
25139
|
compareVersions,
|
|
25081
25140
|
computeBodyChecksum,
|
|
25141
|
+
edgeCarriesProperties,
|
|
25082
25142
|
evaluateAntiPatterns,
|
|
25083
25143
|
findInvalidStatusMigrationTargets,
|
|
25084
25144
|
formatUpgText,
|