@unified-product-graph/core 0.9.12 → 0.9.13
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 +16 -0
- package/dist/index.cjs +47 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +47 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -7027,6 +7027,13 @@ declare const UPG_EDGE_CATALOG: {
|
|
|
7027
7027
|
source_type: string;
|
|
7028
7028
|
target_type: string;
|
|
7029
7029
|
};
|
|
7030
|
+
specification_governed_by_organization: {
|
|
7031
|
+
forward_verb: string;
|
|
7032
|
+
reverse_verb: string;
|
|
7033
|
+
classification: "semantic";
|
|
7034
|
+
source_type: string;
|
|
7035
|
+
target_type: string;
|
|
7036
|
+
};
|
|
7030
7037
|
};
|
|
7031
7038
|
/** The `UPGEdgeType` union derived from the registry above. Declared here (not
|
|
7032
7039
|
* in `shapes/edges.ts`) so the polymorphic list below can reference it
|
|
@@ -19709,12 +19716,26 @@ interface UPGCuratedAntiPattern {
|
|
|
19709
19716
|
* practitioner, not a graph engineer.
|
|
19710
19717
|
*/
|
|
19711
19718
|
description: string;
|
|
19719
|
+
/**
|
|
19720
|
+
* Detection scope.
|
|
19721
|
+
* - `'graph'` (default, omitted): evaluated against a single product graph by
|
|
19722
|
+
* the `evaluateAntiPatterns` chokepoint (validate_graph, get_anti_pattern_violations_for).
|
|
19723
|
+
* - `'portfolio'`: evaluated across products + the shared registry by
|
|
19724
|
+
* `portfolio_validate`. The single-graph evaluator SKIPS these (a portfolio
|
|
19725
|
+
* pattern can never flip a single graph invalid), and they carry no
|
|
19726
|
+
* `structured_condition` because the cross-product detector is not expressible
|
|
19727
|
+
* as an `IntelligenceCondition` over one graph.
|
|
19728
|
+
*/
|
|
19729
|
+
scope?: 'graph' | 'portfolio';
|
|
19712
19730
|
/**
|
|
19713
19731
|
* Machine-evaluable detector. Composes `EntityCheck`,
|
|
19714
19732
|
* `RelationshipCheck`, `BenchmarkCheck`, etc. via `and` / `or`.
|
|
19715
19733
|
* Consumers (Entopo, MCP, the site) evaluate this against a graph.
|
|
19734
|
+
*
|
|
19735
|
+
* Required for graph-scoped patterns; OMITTED for `scope: 'portfolio'`
|
|
19736
|
+
* patterns, whose detector lives in `portfolio_validate` instead.
|
|
19716
19737
|
*/
|
|
19717
|
-
structured_condition
|
|
19738
|
+
structured_condition?: IntelligenceCondition;
|
|
19718
19739
|
/** One sentence on the product impact when this anti-pattern fires. */
|
|
19719
19740
|
why_it_matters: string;
|
|
19720
19741
|
/**
|
|
@@ -20979,7 +21000,7 @@ declare function isCanonical(text: string): boolean;
|
|
|
20979
21000
|
* it stamps the `upg_version` field of every `.upg` file written by the SDK.
|
|
20980
21001
|
* The `check:version-lockstep` gate enforces this at release time.
|
|
20981
21002
|
*/
|
|
20982
|
-
declare const UPG_VERSION: "0.9.
|
|
21003
|
+
declare const UPG_VERSION: "0.9.13";
|
|
20983
21004
|
/**
|
|
20984
21005
|
* The `.upg` JSON document format version. Written to the `upg_version` field.
|
|
20985
21006
|
* Evolves independently from `UPG_VERSION` (the catalogue version).
|
package/dist/index.d.ts
CHANGED
|
@@ -7027,6 +7027,13 @@ declare const UPG_EDGE_CATALOG: {
|
|
|
7027
7027
|
source_type: string;
|
|
7028
7028
|
target_type: string;
|
|
7029
7029
|
};
|
|
7030
|
+
specification_governed_by_organization: {
|
|
7031
|
+
forward_verb: string;
|
|
7032
|
+
reverse_verb: string;
|
|
7033
|
+
classification: "semantic";
|
|
7034
|
+
source_type: string;
|
|
7035
|
+
target_type: string;
|
|
7036
|
+
};
|
|
7030
7037
|
};
|
|
7031
7038
|
/** The `UPGEdgeType` union derived from the registry above. Declared here (not
|
|
7032
7039
|
* in `shapes/edges.ts`) so the polymorphic list below can reference it
|
|
@@ -19709,12 +19716,26 @@ interface UPGCuratedAntiPattern {
|
|
|
19709
19716
|
* practitioner, not a graph engineer.
|
|
19710
19717
|
*/
|
|
19711
19718
|
description: string;
|
|
19719
|
+
/**
|
|
19720
|
+
* Detection scope.
|
|
19721
|
+
* - `'graph'` (default, omitted): evaluated against a single product graph by
|
|
19722
|
+
* the `evaluateAntiPatterns` chokepoint (validate_graph, get_anti_pattern_violations_for).
|
|
19723
|
+
* - `'portfolio'`: evaluated across products + the shared registry by
|
|
19724
|
+
* `portfolio_validate`. The single-graph evaluator SKIPS these (a portfolio
|
|
19725
|
+
* pattern can never flip a single graph invalid), and they carry no
|
|
19726
|
+
* `structured_condition` because the cross-product detector is not expressible
|
|
19727
|
+
* as an `IntelligenceCondition` over one graph.
|
|
19728
|
+
*/
|
|
19729
|
+
scope?: 'graph' | 'portfolio';
|
|
19712
19730
|
/**
|
|
19713
19731
|
* Machine-evaluable detector. Composes `EntityCheck`,
|
|
19714
19732
|
* `RelationshipCheck`, `BenchmarkCheck`, etc. via `and` / `or`.
|
|
19715
19733
|
* Consumers (Entopo, MCP, the site) evaluate this against a graph.
|
|
19734
|
+
*
|
|
19735
|
+
* Required for graph-scoped patterns; OMITTED for `scope: 'portfolio'`
|
|
19736
|
+
* patterns, whose detector lives in `portfolio_validate` instead.
|
|
19716
19737
|
*/
|
|
19717
|
-
structured_condition
|
|
19738
|
+
structured_condition?: IntelligenceCondition;
|
|
19718
19739
|
/** One sentence on the product impact when this anti-pattern fires. */
|
|
19719
19740
|
why_it_matters: string;
|
|
19720
19741
|
/**
|
|
@@ -20979,7 +21000,7 @@ declare function isCanonical(text: string): boolean;
|
|
|
20979
21000
|
* it stamps the `upg_version` field of every `.upg` file written by the SDK.
|
|
20980
21001
|
* The `check:version-lockstep` gate enforces this at release time.
|
|
20981
21002
|
*/
|
|
20982
|
-
declare const UPG_VERSION: "0.9.
|
|
21003
|
+
declare const UPG_VERSION: "0.9.13";
|
|
20983
21004
|
/**
|
|
20984
21005
|
* The `.upg` JSON document format version. Written to the `upg_version` field.
|
|
20985
21006
|
* Evolves independently from `UPG_VERSION` (the catalogue version).
|
package/dist/index.js
CHANGED
|
@@ -2942,7 +2942,9 @@ var UPG_EDGE_CATALOG = {
|
|
|
2942
2942
|
specification_extends_specification: { forward_verb: "extends", reverse_verb: "extended_by", classification: "hierarchy", source_type: "specification", target_type: "specification" },
|
|
2943
2943
|
specification_competes_with_specification: { forward_verb: "competes_with", reverse_verb: "competes_with", classification: "semantic", source_type: "specification", target_type: "specification" },
|
|
2944
2944
|
primitive_defined_by_specification: { forward_verb: "defined_by", reverse_verb: "defines", classification: "semantic", source_type: "primitive", target_type: "specification" },
|
|
2945
|
-
primitive_composes_primitive: { forward_verb: "composes", reverse_verb: "composed_by", classification: "hierarchy", source_type: "primitive", target_type: "primitive" }
|
|
2945
|
+
primitive_composes_primitive: { forward_verb: "composes", reverse_verb: "composed_by", classification: "hierarchy", source_type: "primitive", target_type: "primitive" },
|
|
2946
|
+
// Stewardship: a registry specification is governed by a (registry-hostable) organization (0.9.13).
|
|
2947
|
+
specification_governed_by_organization: { forward_verb: "governed_by", reverse_verb: "governs", classification: "semantic", source_type: "specification", target_type: "organization" }
|
|
2946
2948
|
};
|
|
2947
2949
|
var UPG_POLYMORPHIC_EDGE_KEYS = [
|
|
2948
2950
|
// Universal semantic verbs
|
|
@@ -24178,6 +24180,47 @@ var UPG_ANTI_PATTERNS = [
|
|
|
24178
24180
|
stages: ["beta", "launch", "growth", "mature"],
|
|
24179
24181
|
severity: "medium",
|
|
24180
24182
|
source: { kind: "practitioner", attribution: "Marty Cagan, Inspired (product discovery)" }
|
|
24183
|
+
},
|
|
24184
|
+
// ── Foundations layer (0.9.13): portfolio-scoped, registry-aware ──────────
|
|
24185
|
+
// These read the shared registry + cross-product edges, so they are evaluated
|
|
24186
|
+
// by portfolio_validate, not the single-graph evaluator. They carry no
|
|
24187
|
+
// structured_condition (the detector is cross-product, not a single-graph
|
|
24188
|
+
// IntelligenceCondition).
|
|
24189
|
+
{
|
|
24190
|
+
id: "specification-without-implementer",
|
|
24191
|
+
since: "0.9.13",
|
|
24192
|
+
scope: "portfolio",
|
|
24193
|
+
name: "Specification without implementer",
|
|
24194
|
+
description: "A specification in the shared registry has no product, feature, or api_contract implementing or conforming to it anywhere in the portfolio. A specification nobody implements is a document, not a contract: it states an intent the portfolio never honours.",
|
|
24195
|
+
why_it_matters: "An unimplemented specification carries authority it has not earned. Teams cite it as a standard while no surface actually conforms, so conformance claims cannot be trusted or traced.",
|
|
24196
|
+
remediation: "Link at least one product, feature, or api_contract to the specification via `product_implements_specification`, `product_exposes_specification`, `feature_conforms_to_specification`, or `api_contract_speaks_specification`; or retire the specification from the registry.",
|
|
24197
|
+
stages: ["validation", "build", "beta", "launch", "growth", "mature"],
|
|
24198
|
+
severity: "medium",
|
|
24199
|
+
source: { kind: "fundamental" }
|
|
24200
|
+
},
|
|
24201
|
+
{
|
|
24202
|
+
id: "primitive-scattered-without-canonical",
|
|
24203
|
+
since: "0.9.13",
|
|
24204
|
+
scope: "portfolio",
|
|
24205
|
+
name: "Primitive scattered without a canonical",
|
|
24206
|
+
description: "The same primitive concept appears as a product-local node in two or more products, but no canonical primitive in the shared registry unifies them. Each product redefines the building block on its own terms, so the portfolio carries several drifting copies of one shared idea instead of a single authoritative definition.",
|
|
24207
|
+
why_it_matters: "Scattered primitives drift apart in name, shape, and meaning. Cross-product reasoning breaks because the same concept reads as several unrelated entities, and a change to the shared building block has no single place to land.",
|
|
24208
|
+
remediation: "Define the shared primitive once in the registry with `define_canonical_entity`, then link each product copy via `register_instance` so the building block has one authoritative definition.",
|
|
24209
|
+
stages: ["build", "beta", "launch", "growth", "mature"],
|
|
24210
|
+
severity: "medium",
|
|
24211
|
+
source: { kind: "fundamental" }
|
|
24212
|
+
},
|
|
24213
|
+
{
|
|
24214
|
+
id: "product-reimplements-specification",
|
|
24215
|
+
since: "0.9.13",
|
|
24216
|
+
scope: "portfolio",
|
|
24217
|
+
name: "Specification reimplemented across products",
|
|
24218
|
+
description: "Two or more products independently implement the same registry specification rather than one depending on a shared implementation. Parallel implementations of a single contract multiply the surface that must stay in sync and usually signal a missing shared library or service.",
|
|
24219
|
+
why_it_matters: "Every independent reimplementation of a specification is another place a conformance bug can hide and another copy that drifts from the contract. The cost of a spec change scales with the number of reimplementers.",
|
|
24220
|
+
remediation: "Consolidate onto one implementation that the others depend on (`depends_on_product` / `hosts`), or confirm the duplication is deliberate and record why. Capture the stewarding organization with `create_registry_edge` so the contract has an owner.",
|
|
24221
|
+
stages: ["build", "beta", "launch", "growth", "mature"],
|
|
24222
|
+
severity: "low",
|
|
24223
|
+
source: { kind: "fundamental" }
|
|
24181
24224
|
}
|
|
24182
24225
|
];
|
|
24183
24226
|
function getAntiPatternById(id) {
|
|
@@ -24201,6 +24244,7 @@ function evaluateAntiPatterns(inputs, options) {
|
|
|
24201
24244
|
const idFilter = options?.anti_pattern_ids ? new Set(options.anti_pattern_ids) : void 0;
|
|
24202
24245
|
const fires = [];
|
|
24203
24246
|
for (const ap of UPG_ANTI_PATTERNS) {
|
|
24247
|
+
if (ap.scope === "portfolio" || !ap.structured_condition) continue;
|
|
24204
24248
|
if (severityFilter && ap.severity !== severityFilter) continue;
|
|
24205
24249
|
if (idFilter && !idFilter.has(ap.id)) continue;
|
|
24206
24250
|
if (inputs.productStage && !ap.stages.includes(inputs.productStage)) {
|
|
@@ -24361,6 +24405,7 @@ function buildViolation(ap) {
|
|
|
24361
24405
|
}
|
|
24362
24406
|
function collectTargetEntities(cond) {
|
|
24363
24407
|
const types = /* @__PURE__ */ new Set();
|
|
24408
|
+
if (!cond) return [];
|
|
24364
24409
|
walk(cond);
|
|
24365
24410
|
return [...types].sort();
|
|
24366
24411
|
function walk(c) {
|
|
@@ -27237,7 +27282,7 @@ function isCanonical(text) {
|
|
|
27237
27282
|
}
|
|
27238
27283
|
|
|
27239
27284
|
// src/index.ts
|
|
27240
|
-
var UPG_VERSION = "0.9.
|
|
27285
|
+
var UPG_VERSION = "0.9.13";
|
|
27241
27286
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
27242
27287
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
27243
27288
|
var UPG_TYPES = getTypes();
|