@unified-product-graph/core 0.10.8 → 0.11.0

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.d.cts CHANGED
@@ -129,7 +129,7 @@ interface UPGBaseNode {
129
129
  * AUTO-GENERATED by scripts/generate-property-registry.ts
130
130
  * Do not edit manually. Run: npx tsx scripts/generate-property-registry.ts
131
131
  *
132
- * Generated: 2026-06-13T10:55:29.604Z
132
+ * Generated: 2026-06-14T07:17:48.412Z
133
133
  * Entity types with properties: 319
134
134
  */
135
135
  interface PropertyDefinition {
@@ -7576,6 +7576,18 @@ interface UPGPortfolioDocument {
7576
7576
  * canonical nodes here via `instance_of` cross-edges (`registry/{node_id}`).
7577
7577
  */
7578
7578
  registry?: UPGRegistry;
7579
+ /**
7580
+ * Append-only classification-history stream (UPG 0.11.0). Each entry is a
7581
+ * `competitor_signal` node with `signal_type: 'reclassification'`, auto-emitted
7582
+ * at the classify-write chokepoint when a competitor moves between
7583
+ * classification cells on an axis. Kept here (a portfolio-scoped collection)
7584
+ * rather than in `registry.nodes` so it never pollutes the canonical-vocabulary
7585
+ * tier or the landscape/tree reads, and rather than in a product graph so the
7586
+ * emit stays atomic with the portfolio cross-edge write. Read by
7587
+ * `diff_classification`. Optional and additive: omitted when empty; portfolio
7588
+ * documents without it remain valid.
7589
+ */
7590
+ signals?: UPGBaseNode[];
7579
7591
  }
7580
7592
 
7581
7593
  /**
@@ -10861,12 +10873,39 @@ interface CompetitorSignalProperties {
10861
10873
  /**
10862
10874
  * Kind of move. `feature_launch` = shipped a feature. `pricing_change` = a plan
10863
10875
  * or tier change. `acquisition` / `partnership` / `market_entry` = strategic moves.
10876
+ * `reclassification` = the competitor moved between classification cells on an
10877
+ * axis (e.g. ai_integrated to ai_agentic); auto-emitted at the classify-write
10878
+ * chokepoint and carries `axis` / `from_value` / `to_value` / `competitor`.
10864
10879
  */
10865
- signal_type?: 'feature_launch' | 'pricing_change' | 'acquisition' | 'partnership' | 'market_entry';
10880
+ signal_type?: 'feature_launch' | 'pricing_change' | 'acquisition' | 'partnership' | 'market_entry' | 'reclassification';
10866
10881
  /** One-line factual summary of the move (what shipped, not marketing copy). */
10867
10882
  summary?: string;
10868
10883
  /** Expected impact on our position. */
10869
10884
  impact?: 'high' | 'medium' | 'low';
10885
+ /**
10886
+ * Reclassification only. The qualified id of the competitor that moved, as the
10887
+ * classify cross-edge source (e.g. `p_rival/n_acme`). Identifies both the
10888
+ * subject and its owning product, so `diff_classification({ product })` can
10889
+ * filter the history stream.
10890
+ */
10891
+ competitor?: string;
10892
+ /**
10893
+ * Reclassification only. The `classification_axis` id the move is on (e.g.
10894
+ * `ca_ai_maturity`). Mirrors the axis the superseded and new classify edges
10895
+ * share.
10896
+ */
10897
+ axis?: string;
10898
+ /**
10899
+ * Reclassification only. The prior `classification_value` id the competitor
10900
+ * was classified as before this move (the superseded cell). Absent for a
10901
+ * first-time classification (nothing was superseded).
10902
+ */
10903
+ from_value?: string;
10904
+ /**
10905
+ * Reclassification only. The new `classification_value` id the competitor is
10906
+ * classified as after this move (the cell the new classify edge points at).
10907
+ */
10908
+ to_value?: string;
10870
10909
  /**
10871
10910
  * Provenance: ISO date-time this record was last observed or refreshed.
10872
10911
  * @example "2026-06-13"
@@ -21485,7 +21524,7 @@ declare function isCanonical(text: string): boolean;
21485
21524
  * it stamps the `upg_version` field of every `.upg` file written by the SDK.
21486
21525
  * The `check:version-lockstep` gate enforces this at release time.
21487
21526
  */
21488
- declare const UPG_VERSION: "0.10.8";
21527
+ declare const UPG_VERSION: "0.11.0";
21489
21528
  /**
21490
21529
  * The `.upg` JSON document format version. Written to the `upg_version` field.
21491
21530
  * Evolves independently from `UPG_VERSION` (the catalogue version).
package/dist/index.d.ts CHANGED
@@ -129,7 +129,7 @@ interface UPGBaseNode {
129
129
  * AUTO-GENERATED by scripts/generate-property-registry.ts
130
130
  * Do not edit manually. Run: npx tsx scripts/generate-property-registry.ts
131
131
  *
132
- * Generated: 2026-06-13T10:55:29.604Z
132
+ * Generated: 2026-06-14T07:17:48.412Z
133
133
  * Entity types with properties: 319
134
134
  */
135
135
  interface PropertyDefinition {
@@ -7576,6 +7576,18 @@ interface UPGPortfolioDocument {
7576
7576
  * canonical nodes here via `instance_of` cross-edges (`registry/{node_id}`).
7577
7577
  */
7578
7578
  registry?: UPGRegistry;
7579
+ /**
7580
+ * Append-only classification-history stream (UPG 0.11.0). Each entry is a
7581
+ * `competitor_signal` node with `signal_type: 'reclassification'`, auto-emitted
7582
+ * at the classify-write chokepoint when a competitor moves between
7583
+ * classification cells on an axis. Kept here (a portfolio-scoped collection)
7584
+ * rather than in `registry.nodes` so it never pollutes the canonical-vocabulary
7585
+ * tier or the landscape/tree reads, and rather than in a product graph so the
7586
+ * emit stays atomic with the portfolio cross-edge write. Read by
7587
+ * `diff_classification`. Optional and additive: omitted when empty; portfolio
7588
+ * documents without it remain valid.
7589
+ */
7590
+ signals?: UPGBaseNode[];
7579
7591
  }
7580
7592
 
7581
7593
  /**
@@ -10861,12 +10873,39 @@ interface CompetitorSignalProperties {
10861
10873
  /**
10862
10874
  * Kind of move. `feature_launch` = shipped a feature. `pricing_change` = a plan
10863
10875
  * or tier change. `acquisition` / `partnership` / `market_entry` = strategic moves.
10876
+ * `reclassification` = the competitor moved between classification cells on an
10877
+ * axis (e.g. ai_integrated to ai_agentic); auto-emitted at the classify-write
10878
+ * chokepoint and carries `axis` / `from_value` / `to_value` / `competitor`.
10864
10879
  */
10865
- signal_type?: 'feature_launch' | 'pricing_change' | 'acquisition' | 'partnership' | 'market_entry';
10880
+ signal_type?: 'feature_launch' | 'pricing_change' | 'acquisition' | 'partnership' | 'market_entry' | 'reclassification';
10866
10881
  /** One-line factual summary of the move (what shipped, not marketing copy). */
10867
10882
  summary?: string;
10868
10883
  /** Expected impact on our position. */
10869
10884
  impact?: 'high' | 'medium' | 'low';
10885
+ /**
10886
+ * Reclassification only. The qualified id of the competitor that moved, as the
10887
+ * classify cross-edge source (e.g. `p_rival/n_acme`). Identifies both the
10888
+ * subject and its owning product, so `diff_classification({ product })` can
10889
+ * filter the history stream.
10890
+ */
10891
+ competitor?: string;
10892
+ /**
10893
+ * Reclassification only. The `classification_axis` id the move is on (e.g.
10894
+ * `ca_ai_maturity`). Mirrors the axis the superseded and new classify edges
10895
+ * share.
10896
+ */
10897
+ axis?: string;
10898
+ /**
10899
+ * Reclassification only. The prior `classification_value` id the competitor
10900
+ * was classified as before this move (the superseded cell). Absent for a
10901
+ * first-time classification (nothing was superseded).
10902
+ */
10903
+ from_value?: string;
10904
+ /**
10905
+ * Reclassification only. The new `classification_value` id the competitor is
10906
+ * classified as after this move (the cell the new classify edge points at).
10907
+ */
10908
+ to_value?: string;
10870
10909
  /**
10871
10910
  * Provenance: ISO date-time this record was last observed or refreshed.
10872
10911
  * @example "2026-06-13"
@@ -21485,7 +21524,7 @@ declare function isCanonical(text: string): boolean;
21485
21524
  * it stamps the `upg_version` field of every `.upg` file written by the SDK.
21486
21525
  * The `check:version-lockstep` gate enforces this at release time.
21487
21526
  */
21488
- declare const UPG_VERSION: "0.10.8";
21527
+ declare const UPG_VERSION: "0.11.0";
21489
21528
  /**
21490
21529
  * The `.upg` JSON document format version. Written to the `upg_version` field.
21491
21530
  * Evolves independently from `UPG_VERSION` (the catalogue version).
package/dist/index.js CHANGED
@@ -9738,9 +9738,13 @@ var UPG_PROPERTY_SCHEMA = {
9738
9738
  // CompetitorSignalProperties: Competitor signal: a dated competitor move mapped onto our portfolio.
9739
9739
  competitor_signal: {
9740
9740
  observed_at: { type: "string", description: 'ISO date-time the move was observed. @example "2026-06-10"' },
9741
- signal_type: { type: "string", enum: ["feature_launch", "pricing_change", "acquisition", "partnership", "market_entry"], description: "Kind of move. `feature_launch` = shipped a feature. `pricing_change` = a plan or tier change. `acquisition` / `partnership` / `market_entry` = strategic moves." },
9741
+ signal_type: { type: "string", enum: ["feature_launch", "pricing_change", "acquisition", "partnership", "market_entry", "reclassification"], description: "Kind of move. `feature_launch` = shipped a feature. `pricing_change` = a plan or tier change. `acquisition` / `partnership` / `market_entry` = strategic moves. `reclassification` = the competitor moved between classification cells on an axis (e.g. ai_integrated to ai_agentic); auto-emitted at the classify-write chokepoint and carries `axis` / `from_value` / `to_value` / `competitor`." },
9742
9742
  summary: { type: "string", description: "One-line factual summary of the move (what shipped, not marketing copy)." },
9743
9743
  impact: { type: "string", enum: ["high", "medium", "low"], description: "Expected impact on our position." },
9744
+ competitor: { type: "string", description: "Reclassification only. The qualified id of the competitor that moved, as the classify cross-edge source (e.g. `p_rival/n_acme`). Identifies both the subject and its owning product, so `diff_classification({ product })` can filter the history stream." },
9745
+ axis: { type: "string", description: "Reclassification only. The `classification_axis` id the move is on (e.g. `ca_ai_maturity`). Mirrors the axis the superseded and new classify edges share." },
9746
+ from_value: { type: "string", description: "Reclassification only. The prior `classification_value` id the competitor was classified as before this move (the superseded cell). Absent for a first-time classification (nothing was superseded)." },
9747
+ to_value: { type: "string", description: "Reclassification only. The new `classification_value` id the competitor is classified as after this move (the cell the new classify edge points at)." },
9744
9748
  last_updated: { type: "string", description: 'Provenance: ISO date-time this record was last observed or refreshed. @example "2026-06-13"' },
9745
9749
  source: { type: "string", description: 'Provenance: where this was observed. A changelog, pricing, or docs URL, an analyst report, or a research note. @example "https://www.contentful.com/changelog/"' },
9746
9750
  confidence: {
@@ -28392,7 +28396,11 @@ function portfolioBody(doc) {
28392
28396
  nodes: sortNodes(doc.registry.nodes).map(canonicalNode),
28393
28397
  ...doc.registry.edges && doc.registry.edges.length > 0 ? { edges: sortEdges(doc.registry.edges).map(canonicalEdge) } : {}
28394
28398
  }
28395
- } : {}
28399
+ } : {},
28400
+ // Append-only classification-history stream (0.11.0). Emitted only when
28401
+ // non-empty so existing portfolio files without it stay byte-identical.
28402
+ // Each entry is a competitor_signal node (serialised with the node rules).
28403
+ ...doc.signals && doc.signals.length > 0 ? { signals: sortNodes(doc.signals).map(canonicalNode) } : {}
28396
28404
  };
28397
28405
  }
28398
28406
  function computeBodyChecksum(doc) {
@@ -28508,6 +28516,10 @@ function normalizeDocument(obj) {
28508
28516
  ...Array.isArray(rawRegistry.edges) ? { edges: rawRegistry.edges } : {}
28509
28517
  };
28510
28518
  }
28519
+ const rawSignals = raw.signals;
28520
+ if (Array.isArray(rawSignals) && rawSignals.length > 0) {
28521
+ out2.signals = rawSignals.map((n) => repairNodeDrift(n));
28522
+ }
28511
28523
  return out2;
28512
28524
  }
28513
28525
  const out = {
@@ -28532,7 +28544,7 @@ function isCanonical(text) {
28532
28544
  }
28533
28545
 
28534
28546
  // src/index.ts
28535
- var UPG_VERSION = "0.10.8";
28547
+ var UPG_VERSION = "0.11.0";
28536
28548
  var UPG_FORMAT_VERSION = "0.4.0";
28537
28549
  var MARKDOWN_FORMAT_VERSION = "0.1";
28538
28550
  var UPG_TYPES = getTypes();