@unified-product-graph/core 0.10.2 → 0.10.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/dist/index.cjs +108 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -32
- package/dist/index.d.ts +79 -32
- package/dist/index.js +105 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
BUSINESS_GROWTH_METRIC_DRIVEN_PLAYBOOK: () => BUSINESS_GROWTH_METRIC_DRIVEN_PLAYBOOK,
|
|
25
25
|
BUSINESS_GTM_GROWTH_PLAYBOOK: () => BUSINESS_GTM_GROWTH_PLAYBOOK,
|
|
26
26
|
BUSINESS_MARKETING_AUDIENCE_FIRST_PLAYBOOK: () => BUSINESS_MARKETING_AUDIENCE_FIRST_PLAYBOOK,
|
|
27
|
+
CLASSIFICATION_EDGE_PROPERTY_SCHEMA: () => CLASSIFICATION_EDGE_PROPERTY_SCHEMA,
|
|
27
28
|
CONTENT_DEPTH_WARNING_RULES: () => CONTENT_DEPTH_WARNING_RULES,
|
|
28
29
|
DEFAULT_ENTITY_EMOJI: () => DEFAULT_ENTITY_EMOJI,
|
|
29
30
|
DISCOVERY_RESEARCH_VALIDATION_PLAYBOOK: () => DISCOVERY_RESEARCH_VALIDATION_PLAYBOOK,
|
|
@@ -135,6 +136,7 @@ __export(index_exports, {
|
|
|
135
136
|
getDomainForType: () => getDomainForType,
|
|
136
137
|
getDomainIdForType: () => getDomainIdForType,
|
|
137
138
|
getDomainsInRing: () => getDomainsInRing,
|
|
139
|
+
getEdgePropertySchema: () => getEdgePropertySchema,
|
|
138
140
|
getEnumScale: () => getEnumScale,
|
|
139
141
|
getEnumValueMeta: () => getEnumValueMeta,
|
|
140
142
|
getGuideForDomain: () => getGuideForDomain,
|
|
@@ -199,6 +201,7 @@ __export(index_exports, {
|
|
|
199
201
|
ringOrderedDomainIds: () => ringOrderedDomainIds,
|
|
200
202
|
rotateSlug: () => rotateSlug,
|
|
201
203
|
serializeCanonical: () => serializeCanonical,
|
|
204
|
+
validateEdgeProperties: () => validateEdgeProperties,
|
|
202
205
|
validateProductStageStrict: () => validateProductStageStrict,
|
|
203
206
|
validateUPGDocument: () => validateUPGDocument,
|
|
204
207
|
validateUPGFramework: () => validateUPGFramework,
|
|
@@ -1185,6 +1188,32 @@ function getTypeName(typeId) {
|
|
|
1185
1188
|
|
|
1186
1189
|
// src/catalog/edge-catalog.ts
|
|
1187
1190
|
var UPG_WILDCARD_ENDPOINT = "node";
|
|
1191
|
+
var CLASSIFICATION_EDGE_PROPERTY_SCHEMA = {
|
|
1192
|
+
confidence: {
|
|
1193
|
+
type: "assessment",
|
|
1194
|
+
scale_id: "confidence_5",
|
|
1195
|
+
description: "How sure we are this node belongs in this classification cell, on the canonical confidence_5 scale. Numeric value plus a high/medium/low label.",
|
|
1196
|
+
properties: {
|
|
1197
|
+
value: { type: "number", description: "Numeric value 1-5 (confidence_5)." },
|
|
1198
|
+
label: { type: "string", description: "Qualitative label (Guessing/Hunch/Some evidence/Confident/Data-backed, or high/medium/low)." },
|
|
1199
|
+
scale_id: { type: "string", description: "Scale rated on (optional; defaults confidence_5)." },
|
|
1200
|
+
normalized: { type: "number", description: "Normalized 0-1 value for cross-tool comparison (optional)." }
|
|
1201
|
+
},
|
|
1202
|
+
required: ["value", "label"]
|
|
1203
|
+
},
|
|
1204
|
+
assessed_on: {
|
|
1205
|
+
type: "string",
|
|
1206
|
+
description: 'Provenance: ISO date-time the classification was made or last re-checked. Drives staleness queries. @example "2026-06-13"'
|
|
1207
|
+
},
|
|
1208
|
+
rationale: {
|
|
1209
|
+
type: "string",
|
|
1210
|
+
description: "Optional. Short note on why this node sits in this cell. Edge-level, distinct from classification_value.rationale (why the value exists as a category)."
|
|
1211
|
+
},
|
|
1212
|
+
evidence: {
|
|
1213
|
+
type: "string",
|
|
1214
|
+
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)."
|
|
1215
|
+
}
|
|
1216
|
+
};
|
|
1188
1217
|
var UPG_EDGE_CATALOG = {
|
|
1189
1218
|
// ── Part 1: Core Narrative Spine (Ring 1) ──────────────────────────────────
|
|
1190
1219
|
// 1.1 User Domain
|
|
@@ -1357,7 +1386,13 @@ var UPG_EDGE_CATALOG = {
|
|
|
1357
1386
|
// competitor can be classified directly against a `registry/{classification_value}`
|
|
1358
1387
|
// canonical, eliminating the per-graph taxonomy node. Within-graph (the catalogue
|
|
1359
1388
|
// case) here; cross-product against the registry canonical via create_cross_product_edge.
|
|
1360
|
-
competitor_classified_as_classification_value: { forward_verb: "classified_as", reverse_verb: "classification_of", classification: "semantic", source_type: "competitor", target_type: "classification_value" },
|
|
1389
|
+
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 },
|
|
1390
|
+
// 0.10.3: the polymorphic, type-agnostic sibling. ANY node (a feature, a
|
|
1391
|
+
// product, a market_segment) classified against a classification_value, so
|
|
1392
|
+
// classification is not welded to the competitor type. Also dual-registered as
|
|
1393
|
+
// a cross-edge for the registry-canonical case. source_type:'node' (wildcard);
|
|
1394
|
+
// listed in UPG_POLYMORPHIC_EDGE_KEYS.
|
|
1395
|
+
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 },
|
|
1361
1396
|
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" },
|
|
1362
1397
|
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" },
|
|
1363
1398
|
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" },
|
|
@@ -3195,7 +3230,9 @@ var UPG_POLYMORPHIC_EDGE_KEYS = [
|
|
|
3195
3230
|
// Universal architecture references
|
|
3196
3231
|
"node_belongs_to_bounded_context",
|
|
3197
3232
|
// Framework exercises (an exercise can include any entity type)
|
|
3198
|
-
"framework_exercise_includes_node"
|
|
3233
|
+
"framework_exercise_includes_node",
|
|
3234
|
+
// Universal classification (any node classified against a classification_value)
|
|
3235
|
+
"node_classified_as_classification_value"
|
|
3199
3236
|
];
|
|
3200
3237
|
var _POLY_KEY_SET = new Set(UPG_POLYMORPHIC_EDGE_KEYS);
|
|
3201
3238
|
function isPolymorphicEdge(key) {
|
|
@@ -3209,6 +3246,10 @@ function edgeCarriesProperties(type) {
|
|
|
3209
3246
|
const def = UPG_EDGE_CATALOG[type];
|
|
3210
3247
|
return def?.carries_properties === true;
|
|
3211
3248
|
}
|
|
3249
|
+
function getEdgePropertySchema(type) {
|
|
3250
|
+
const def = UPG_EDGE_CATALOG[type];
|
|
3251
|
+
return def?.property_schema;
|
|
3252
|
+
}
|
|
3212
3253
|
|
|
3213
3254
|
// src/catalog/legacy-product-stages.ts
|
|
3214
3255
|
var LEGACY_PRODUCT_STAGES = Object.freeze({
|
|
@@ -3253,7 +3294,8 @@ var UPG_CROSS_EDGE_TYPES = [
|
|
|
3253
3294
|
"feature_rivals_competitor_feature",
|
|
3254
3295
|
"competitor_signal_maps_to_feature",
|
|
3255
3296
|
"competitor_signal_surfaces_opportunity",
|
|
3256
|
-
"competitor_classified_as_classification_value"
|
|
3297
|
+
"competitor_classified_as_classification_value",
|
|
3298
|
+
"node_classified_as_classification_value"
|
|
3257
3299
|
];
|
|
3258
3300
|
var REGISTRY_PRODUCT_ID = "registry";
|
|
3259
3301
|
|
|
@@ -18738,6 +18780,65 @@ function isUPGDocument(doc) {
|
|
|
18738
18780
|
return validateUPGDocument(doc).valid;
|
|
18739
18781
|
}
|
|
18740
18782
|
|
|
18783
|
+
// src/properties/edge-property-validation.ts
|
|
18784
|
+
function validateEdgeProperties(edgeType, properties) {
|
|
18785
|
+
const schema = getEdgePropertySchema(edgeType);
|
|
18786
|
+
if (!schema || !properties) return [];
|
|
18787
|
+
const errors = [];
|
|
18788
|
+
const allowed = Object.keys(schema);
|
|
18789
|
+
for (const key of Object.keys(properties)) {
|
|
18790
|
+
if (!allowed.includes(key)) {
|
|
18791
|
+
errors.push(`unknown property "${key}" for edge type "${edgeType}" (allowed: ${allowed.join(", ")})`);
|
|
18792
|
+
}
|
|
18793
|
+
}
|
|
18794
|
+
for (const [key, def] of Object.entries(schema)) {
|
|
18795
|
+
const val = properties[key];
|
|
18796
|
+
if (val === void 0 || val === null) continue;
|
|
18797
|
+
errors.push(...validateValue(key, def, val));
|
|
18798
|
+
}
|
|
18799
|
+
return errors;
|
|
18800
|
+
}
|
|
18801
|
+
function validateValue(key, def, val) {
|
|
18802
|
+
const errors = [];
|
|
18803
|
+
switch (def.type) {
|
|
18804
|
+
case "string":
|
|
18805
|
+
if (typeof val !== "string") errors.push(`property "${key}" must be a string`);
|
|
18806
|
+
break;
|
|
18807
|
+
case "number":
|
|
18808
|
+
if (typeof val !== "number") errors.push(`property "${key}" must be a number`);
|
|
18809
|
+
break;
|
|
18810
|
+
case "boolean":
|
|
18811
|
+
if (typeof val !== "boolean") errors.push(`property "${key}" must be a boolean`);
|
|
18812
|
+
break;
|
|
18813
|
+
case "assessment": {
|
|
18814
|
+
if (typeof val !== "object" || Array.isArray(val)) {
|
|
18815
|
+
errors.push(`property "${key}" must be an assessment object with value and label`);
|
|
18816
|
+
break;
|
|
18817
|
+
}
|
|
18818
|
+
const a = val;
|
|
18819
|
+
for (const r of def.required ?? ["value", "label"]) {
|
|
18820
|
+
if (a[r] === void 0 || a[r] === null) errors.push(`assessment "${key}" is missing required "${r}"`);
|
|
18821
|
+
}
|
|
18822
|
+
if (a.value !== void 0 && a.value !== null) {
|
|
18823
|
+
if (typeof a.value !== "number") {
|
|
18824
|
+
errors.push(`assessment "${key}".value must be a number`);
|
|
18825
|
+
} else {
|
|
18826
|
+
const scaleId = (typeof a.scale_id === "string" ? a.scale_id : void 0) ?? def.scale_id;
|
|
18827
|
+
const scale = scaleId ? getScale(scaleId) : void 0;
|
|
18828
|
+
if (scale && (a.value < scale.min || a.value > scale.max)) {
|
|
18829
|
+
errors.push(`assessment "${key}".value ${a.value} is out of range ${scale.min}-${scale.max} for scale ${scaleId}`);
|
|
18830
|
+
}
|
|
18831
|
+
}
|
|
18832
|
+
}
|
|
18833
|
+
if (typeof a.scale_id === "string" && def.scale_id !== void 0 && a.scale_id !== def.scale_id) {
|
|
18834
|
+
errors.push(`assessment "${key}".scale_id "${a.scale_id}" must be "${def.scale_id}"`);
|
|
18835
|
+
}
|
|
18836
|
+
break;
|
|
18837
|
+
}
|
|
18838
|
+
}
|
|
18839
|
+
return errors;
|
|
18840
|
+
}
|
|
18841
|
+
|
|
18741
18842
|
// src/presentation/entity-emoji.ts
|
|
18742
18843
|
var DEFAULT_ENTITY_EMOJI = "\u{1F4E6}";
|
|
18743
18844
|
var ENTITY_EMOJI = {
|
|
@@ -28637,7 +28738,7 @@ function isCanonical(text) {
|
|
|
28637
28738
|
}
|
|
28638
28739
|
|
|
28639
28740
|
// src/index.ts
|
|
28640
|
-
var UPG_VERSION = "0.10.
|
|
28741
|
+
var UPG_VERSION = "0.10.4";
|
|
28641
28742
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
28642
28743
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
28643
28744
|
var UPG_TYPES = getTypes();
|
|
@@ -28706,6 +28807,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
28706
28807
|
BUSINESS_GROWTH_METRIC_DRIVEN_PLAYBOOK,
|
|
28707
28808
|
BUSINESS_GTM_GROWTH_PLAYBOOK,
|
|
28708
28809
|
BUSINESS_MARKETING_AUDIENCE_FIRST_PLAYBOOK,
|
|
28810
|
+
CLASSIFICATION_EDGE_PROPERTY_SCHEMA,
|
|
28709
28811
|
CONTENT_DEPTH_WARNING_RULES,
|
|
28710
28812
|
DEFAULT_ENTITY_EMOJI,
|
|
28711
28813
|
DISCOVERY_RESEARCH_VALIDATION_PLAYBOOK,
|
|
@@ -28817,6 +28919,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
28817
28919
|
getDomainForType,
|
|
28818
28920
|
getDomainIdForType,
|
|
28819
28921
|
getDomainsInRing,
|
|
28922
|
+
getEdgePropertySchema,
|
|
28820
28923
|
getEnumScale,
|
|
28821
28924
|
getEnumValueMeta,
|
|
28822
28925
|
getGuideForDomain,
|
|
@@ -28881,6 +28984,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
28881
28984
|
ringOrderedDomainIds,
|
|
28882
28985
|
rotateSlug,
|
|
28883
28986
|
serializeCanonical,
|
|
28987
|
+
validateEdgeProperties,
|
|
28884
28988
|
validateProductStageStrict,
|
|
28885
28989
|
validateUPGDocument,
|
|
28886
28990
|
validateUPGFramework,
|