@unified-product-graph/core 0.23.2 → 0.25.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/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/dist/index.cjs +151 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +187 -3
- package/dist/index.d.ts +187 -3
- package/dist/index.js +151 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -214,7 +214,7 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
214
214
|
|
|
215
215
|
## [0.14.1] - 2026-06-17
|
|
216
216
|
|
|
217
|
-
**Release rider: a browser-safe `crypto` import in the canonical serialiser (unblocks
|
|
217
|
+
**Release rider: a browser-safe `crypto` import in the canonical serialiser (unblocks browser bundlers).** The canonical serialiser imported `crypto` in a form that broke browser bundlers; it is namespaced to `node:crypto`. Fix only.
|
|
218
218
|
|
|
219
219
|
### Fixed
|
|
220
220
|
- Browser-safe `crypto` import in `format/canonical.ts`.
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
The TypeScript core for the **Unified Product Graph (UPG)**, an open specification that gives product tools a shared vocabulary for entities, edges, and frameworks.
|
|
9
9
|
|
|
10
|
-
320 entity types across 37 domains.
|
|
10
|
+
320 entity types across 37 domains. 1058 typed edges. 46 canonical framework definitions, with more added as each is reviewed.
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
package/dist/index.cjs
CHANGED
|
@@ -3508,7 +3508,105 @@ var UPG_EDGE_CATALOG = {
|
|
|
3508
3508
|
// product's feature or capability, authored in a different graph within the
|
|
3509
3509
|
// portfolio, fits the 0.17.3 locked predicate.
|
|
3510
3510
|
objective_defers_feature: { forward_verb: "defers", reverse_verb: "deferred_by", classification: "cross-domain", source_type: "objective", target_type: "feature", carries_properties: true, property_schema: DEFER_EDGE_PROPERTY_SCHEMA, cross_product_eligible: true, deliberate_only: true },
|
|
3511
|
-
objective_defers_capability: { forward_verb: "defers", reverse_verb: "deferred_by", classification: "semantic", source_type: "objective", target_type: "capability", carries_properties: true, property_schema: DEFER_EDGE_PROPERTY_SCHEMA, cross_product_eligible: true, deliberate_only: true }
|
|
3511
|
+
objective_defers_capability: { forward_verb: "defers", reverse_verb: "deferred_by", classification: "semantic", source_type: "objective", target_type: "capability", carries_properties: true, property_schema: DEFER_EDGE_PROPERTY_SCHEMA, cross_product_eligible: true, deliberate_only: true },
|
|
3512
|
+
// ── Enterprise GTM coordination batch (0.24.0, Track 1 Wave A) ───────────────
|
|
3513
|
+
// The catalog modelled each go-to-market department's nouns but almost none of
|
|
3514
|
+
// the handoffs between them, and the enterprise motion IS the handoffs (audit
|
|
3515
|
+
// `2026-07-16-enterprise-gtm-coverage-audit.md`, §3). Sixteen additive edges
|
|
3516
|
+
// wire the buying committee onto the deal, give the enablement lattice a demand
|
|
3517
|
+
// side, close the pre-sale win/loss LEARN loop, make post-sale account-scoped,
|
|
3518
|
+
// and complete the audience-projection lattice. None are hierarchy — every one
|
|
3519
|
+
// is a lateral coordination link — so UPG_VALID_CHILDREN is untouched. Verbs
|
|
3520
|
+
// are precedent-matched (cited per row); classification per the standard
|
|
3521
|
+
// taxonomy. Two edges are portfolio-crossing by construction (a deal in a
|
|
3522
|
+
// field-ops graph blocked by a feature in a product graph; a win/loss study in
|
|
3523
|
+
// a research graph analysing a deal in another) → cross_product_eligible at
|
|
3524
|
+
// mint, one line rather than a later migration (audit §7-addendum decision 6).
|
|
3525
|
+
// Buying committee (F2). A contact was reachable only via account_contains_contact;
|
|
3526
|
+
// it could not attach to the deal it influences. This is the substrate of every
|
|
3527
|
+
// qualification framework (MEDDICC/SPICED) and of multi-threading. Semantic, not
|
|
3528
|
+
// hierarchy: the contact is parented under its account (account_contains_contact),
|
|
3529
|
+
// so a deal references it laterally, not by containment; and semantic, not
|
|
3530
|
+
// cross-domain, because deal and contact are both in the sales domain (T1.7
|
|
3531
|
+
// guardrail: a within-domain edge is not cross-domain). @example deal "Northwind
|
|
3532
|
+
// platform expansion" involves contact "VP Engineering" (buying_role: 'economic_buyer').
|
|
3533
|
+
deal_involves_contact: { forward_verb: "involves", reverse_verb: "involved_in", classification: "semantic", source_type: "deal", target_type: "contact" },
|
|
3534
|
+
// Enablement demand side (F3). GTM's objection→rebuttal→proof_point chain had
|
|
3535
|
+
// supply but nothing consuming it in a deal context. Mirrors the positioning
|
|
3536
|
+
// precedent (positioning_challenged_by_objection). @example deal "Northwind
|
|
3537
|
+
// platform expansion" challenged_by objection "no SOC 2 report yet".
|
|
3538
|
+
deal_challenged_by_objection: { forward_verb: "challenged_by", reverse_verb: "challenges", classification: "cross-domain", source_type: "deal", target_type: "objection" },
|
|
3539
|
+
// Enablement deployed in context (F3). Which battlecard was armed on which deal.
|
|
3540
|
+
// Mirrors gtm_strategy_arms_with_competitive_battle_card. @example deal armed_with
|
|
3541
|
+
// competitive_battle_card "vs. Meridian Cloud".
|
|
3542
|
+
deal_armed_with_competitive_battle_card: { forward_verb: "armed_with", reverse_verb: "arms", classification: "cross-domain", source_type: "deal", target_type: "competitive_battle_card" },
|
|
3543
|
+
// Loss cause (F3). Gives competitive_battle_card.win_rate its derivation path —
|
|
3544
|
+
// nothing in the graph could previously compute it. Causal (a directional
|
|
3545
|
+
// outcome), mirroring lead_becomes_account. @example deal "Sterling Data Systems
|
|
3546
|
+
// renewal" lost_to competitor "Meridian Cloud".
|
|
3547
|
+
deal_lost_to_competitor: { forward_verb: "lost_to", reverse_verb: "won", classification: "causal", source_type: "deal", target_type: "competitor" },
|
|
3548
|
+
// Close mechanism (F4). MSA/SOW/order form reachable from the deal; contract
|
|
3549
|
+
// previously bound only legal_entity and partnership. Mirrors
|
|
3550
|
+
// deal_quoted_via_quote_document. @example deal closed_via contract "Northwind MSA".
|
|
3551
|
+
deal_closed_via_contract: { forward_verb: "closed_via", reverse_verb: "closes", classification: "cross-domain", source_type: "deal", target_type: "contract" },
|
|
3552
|
+
// Pipeline blocker (F5). "Which roadmap items unblock how much pipeline"; plugs
|
|
3553
|
+
// into change_blast_radius. Mirrors epic_affected_by_bug. cross_product_eligible:
|
|
3554
|
+
// the deal lives in the field-ops graph, the blocking feature in the product
|
|
3555
|
+
// graph. @example deal blocked_by feature "SAML SSO".
|
|
3556
|
+
deal_blocked_by_feature: { forward_verb: "blocked_by", reverse_verb: "blocks", classification: "cross-domain", source_type: "deal", target_type: "feature", cross_product_eligible: true },
|
|
3557
|
+
// Win/loss LEARN loop (F3). Win/loss analysis is a research genre, not a new
|
|
3558
|
+
// type — a research_study analyses the deal. Closes the pre-sale learning loop
|
|
3559
|
+
// (the post-sale one already existed via support_ticket_reveals_need). Mirrors
|
|
3560
|
+
// proof_point_derived_from_insight's provenance shape. cross_product_eligible:
|
|
3561
|
+
// the study may live in a research graph distinct from the deal's field-ops
|
|
3562
|
+
// graph. @example research_study "Q3 competitive win/loss" analyzes deal
|
|
3563
|
+
// "Sterling Data Systems renewal".
|
|
3564
|
+
research_study_analyzes_deal: { forward_verb: "analyzes", reverse_verb: "analyzed_by", classification: "cross-domain", source_type: "research_study", target_type: "deal", cross_product_eligible: true },
|
|
3565
|
+
// Account-scoped sensing (F5). Nearly every CS edge hung off product; only one
|
|
3566
|
+
// scoped anything to an account. Mirrors product_supports_via_support_ticket.
|
|
3567
|
+
// @example account "Northwind Logistics" raises support_ticket "onboarding SSO
|
|
3568
|
+
// blocker".
|
|
3569
|
+
account_raises_support_ticket: { forward_verb: "raises", reverse_verb: "raised_by", classification: "cross-domain", source_type: "account", target_type: "support_ticket" },
|
|
3570
|
+
// Account health (F5). Mirrors product_health_scored_via_customer_health_score.
|
|
3571
|
+
// @example account health_scored_via customer_health_score "Northwind Q3 health".
|
|
3572
|
+
account_health_scored_via_customer_health_score: { forward_verb: "health_scored_via", reverse_verb: "scores", classification: "cross-domain", source_type: "account", target_type: "customer_health_score" },
|
|
3573
|
+
// Account churn (F5). Churn lands on the account, not just the product. Mirrors
|
|
3574
|
+
// product_loses_because_churn_reason. @example account lost_because churn_reason
|
|
3575
|
+
// "switched to incumbent suite".
|
|
3576
|
+
account_lost_because_churn_reason: { forward_verb: "lost_because", reverse_verb: "causes_churn_for", classification: "cross-domain", source_type: "account", target_type: "churn_reason" },
|
|
3577
|
+
// Onboarding / implementation (F5). Reuses the Program Management machinery
|
|
3578
|
+
// (project/milestone/deliverable/status_report) for enterprise onboarding.
|
|
3579
|
+
// Mirrors the operate-a-thing-via-a-plan shape of product_operated_via_playbook.
|
|
3580
|
+
// @example account implements_via project "Northwind rollout".
|
|
3581
|
+
account_implements_via_project: { forward_verb: "implements_via", reverse_verb: "implements", classification: "cross-domain", source_type: "account", target_type: "project" },
|
|
3582
|
+
// Renewal object-path (F5). A renewal is a deal of deal_type 'renewal'; this
|
|
3583
|
+
// completes the lead→account→deal→subscription→deal cycle. Causal (a directional
|
|
3584
|
+
// renewal event), mirroring quote_document_advances_deal. @example subscription
|
|
3585
|
+
// "Northwind annual" renews_via deal "Northwind FY27 renewal".
|
|
3586
|
+
subscription_renews_via_deal: { forward_verb: "renews_via", reverse_verb: "renews", classification: "causal", source_type: "subscription", target_type: "deal" },
|
|
3587
|
+
// Enterprise early access (F5, rider R1). An account participates in a beta
|
|
3588
|
+
// program. Mirrors product_runs_beta_program's noun. @example account
|
|
3589
|
+
// participates_in beta_program "SSO private beta".
|
|
3590
|
+
account_participates_in_beta_program: { forward_verb: "participates_in", reverse_verb: "has_participant", classification: "cross-domain", source_type: "account", target_type: "beta_program" },
|
|
3591
|
+
// Security gate (F4, rider R2). The security questionnaire/review as a deal gate,
|
|
3592
|
+
// reusing the Security noun rather than minting security_questionnaire. Mirrors
|
|
3593
|
+
// service_level_agreement_covers_account's account↔security cross-domain shape.
|
|
3594
|
+
// @example deal gated_by security_review "Northwind vendor security assessment".
|
|
3595
|
+
deal_gated_by_security_review: { forward_verb: "gated_by", reverse_verb: "gates", classification: "cross-domain", source_type: "deal", target_type: "security_review" },
|
|
3596
|
+
// Audience-projection subject axis (Ruling 4, A15). messaging's only subject edge
|
|
3597
|
+
// was positioning_communicated_via_messaging — messaging could not be ABOUT a
|
|
3598
|
+
// feature, so audience-scoped feature projections were unexpressable at the root.
|
|
3599
|
+
// Mirrors the positioning precedent. The rendered projection is NOT stored (views
|
|
3600
|
+
// philosophy); this edge stores the atom the lens queries. @example feature "SAML
|
|
3601
|
+
// SSO" communicated_via messaging "SSO beta enablement one-pager".
|
|
3602
|
+
feature_communicated_via_messaging: { forward_verb: "communicated_via", reverse_verb: "communicates", classification: "cross-domain", source_type: "feature", target_type: "messaging" },
|
|
3603
|
+
// Launch coordination seam (Ruling 4, A16). launch had edges to
|
|
3604
|
+
// release/feature/channel/campaign/metric/messaging but none to Program
|
|
3605
|
+
// Management — the GTM readiness checklist (who builds the demo env, trains the
|
|
3606
|
+
// SEs, by when) had no home. Reuses project/milestone/deliverable, the same move
|
|
3607
|
+
// as account_implements_via_project. @example launch "SSO GA" coordinated_via
|
|
3608
|
+
// project "SSO launch readiness".
|
|
3609
|
+
launch_coordinated_via_project: { forward_verb: "coordinated_via", reverse_verb: "coordinates", classification: "cross-domain", source_type: "launch", target_type: "project" }
|
|
3512
3610
|
};
|
|
3513
3611
|
var UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES = Object.keys(UPG_EDGE_CATALOG).filter(
|
|
3514
3612
|
(k) => UPG_EDGE_CATALOG[k].cross_product_eligible === true
|
|
@@ -6816,6 +6914,8 @@ var PROPERTY_SCALE_MAP = {
|
|
|
6816
6914
|
// market/risk (UPG-579 Option B)
|
|
6817
6915
|
probability: "confidence_5",
|
|
6818
6916
|
// sales/forecast (UPG-579 Option B)
|
|
6917
|
+
qualification_score: "confidence_5",
|
|
6918
|
+
// sales/deal — how confident the qualification is (0.24.0)
|
|
6819
6919
|
// ── Effort ───────────────────────────────────────────────────────────────
|
|
6820
6920
|
effort: "effort_5",
|
|
6821
6921
|
// discovery
|
|
@@ -10310,7 +10410,10 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
10310
10410
|
account: {
|
|
10311
10411
|
account_type: { type: "string", enum: ["prospect", "customer", "partner", "churned"], description: "Relationship status of this account" },
|
|
10312
10412
|
industry: { type: "string", description: "Industry vertical the account operates in" },
|
|
10313
|
-
employee_count: { type: "number", description: "Number of employees at the account", modifier: "snapshot" }
|
|
10413
|
+
employee_count: { type: "number", description: "Number of employees at the account", modifier: "snapshot" },
|
|
10414
|
+
segment: { type: "string", enum: ["smb", "mid_market", "enterprise", "strategic"], description: "Go-to-market tier this account is served at. A segmentation *decision* (how the field org treats the account), distinct from `employee_count` (a raw fact) and aligned with but not identical to the ideal customer profile's `company_size` buckets. `strategic` is the tier that escalates to a dedicated account-plan graph (Tier 3 client model)." },
|
|
10415
|
+
annual_contract_value: { type: "number", description: "Annual contract value in the account's billing currency. The single most common enterprise account-tiering input; a snapshot that changes on expansion or renewal.", modifier: "snapshot" },
|
|
10416
|
+
region: { type: "string", description: 'Geographic region the account is managed in (e.g. "EMEA", "NA-West"). Free-form: territory taxonomies vary by org and are modelled structurally via the `territory` entity when they need to be queryable.' }
|
|
10314
10417
|
},
|
|
10315
10418
|
// AcquisitionChannelProperties: AcquisitionChannel entity.
|
|
10316
10419
|
acquisition_channel: {
|
|
@@ -10899,7 +11002,8 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
10899
11002
|
// ContactProperties: Contact.
|
|
10900
11003
|
contact: {
|
|
10901
11004
|
contact_role: { type: "string", description: "Job title or role within the account" },
|
|
10902
|
-
is_decision_maker: { type: "boolean", description: "Whether this person has purchasing authority" }
|
|
11005
|
+
is_decision_maker: { type: "boolean", description: "Whether this person has purchasing authority" },
|
|
11006
|
+
buying_role: { type: "string", enum: ["champion", "economic_buyer", "technical_evaluator", "end_user", "detractor", "influencer", "procurement", "legal", "security"], description: "Role this contact plays in the buying committee (the decision-making unit). The substrate of enterprise multi-threading and of qualification frameworks (MEDDICC/SPICED): a deal with no `champion` and no `economic_buyer` mapped is single-threaded and at risk. `is_decision_maker` becomes largely derivable (`buying_role = economic_buyer`) but is kept for back-compat. @example 'economic_buyer'" }
|
|
10903
11007
|
},
|
|
10904
11008
|
// ContentCalendarProperties: Content calendar.
|
|
10905
11009
|
content_calendar: {
|
|
@@ -11095,7 +11199,24 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
11095
11199
|
deal: {
|
|
11096
11200
|
deal_value: { type: "number", description: "Monetary value of the deal" },
|
|
11097
11201
|
close_date: { type: "string", description: "Expected close date (ISO format)" },
|
|
11098
|
-
probability: { type: "number", description: "Likelihood of closing (0-100%)" }
|
|
11202
|
+
probability: { type: "number", description: "Likelihood of closing (0-100%)" },
|
|
11203
|
+
deal_outcome: { type: "string", enum: ["won", "lost", "no_decision"], description: "Terminal result of the deal. An Event-axis outcome (the verdict on a one-time event), NOT a lifecycle phase, so it is `deal_outcome` and not `deal_status` per the status-convention Rule 3. Lifecycle (open/won/lost as phases) belongs on the base `status` slot; this records the win/loss verdict a closed deal carries and gives `deal_lost_to_competitor` / win-loss study derivations their anchor. @example 'won'" },
|
|
11204
|
+
deal_type: { type: "string", enum: ["new_business", "expansion", "renewal"], description: "Motion this deal belongs to. Mirrors `PipelineSales.pipeline_type` at the deal grain; `renewal` is the value `subscription_renews_via_deal` points at. @example 'expansion'" },
|
|
11205
|
+
next_step: { type: "string", description: "The single most-used CRM field: the next concrete action to move the deal. Free text on purpose (a coordination note, not a structured task). @example 'Send security questionnaire to procurement'" },
|
|
11206
|
+
next_step_date: { type: "string", description: "When the `next_step` is due (ISO format)." },
|
|
11207
|
+
qualification_framework: { type: "string", enum: ["meddicc", "bant", "spiced", "custom"], description: "Qualification framework this deal is scored against. Names the rubric so the `qualification_score` is interpretable; per-pillar booleans (MEDDICC's Metrics / Economic buyer / Decision criteria / \u2026) are deferred until `custom` recurrence proves the demand. @example 'meddicc'" },
|
|
11208
|
+
qualification_score: {
|
|
11209
|
+
type: "assessment",
|
|
11210
|
+
scale_id: "confidence_5",
|
|
11211
|
+
description: "How well-qualified the deal is, on the canonical `confidence_5` scale (UPGAssessment: numeric value plus a high/medium/low label). Coarse by design; the granular per-pillar breakdown is deferred (see `qualification_framework`).",
|
|
11212
|
+
properties: {
|
|
11213
|
+
value: { type: "number", description: "The numeric value, used for computation." },
|
|
11214
|
+
label: { type: "string", description: "The qualitative label (what the assessor meant)." },
|
|
11215
|
+
scale_id: { type: "string", description: "Which assessment scale this was rated on (optional)." },
|
|
11216
|
+
normalized: { type: "number", description: "Normalized 0-1 value for cross-tool comparison (optional)." }
|
|
11217
|
+
},
|
|
11218
|
+
required: ["value", "label"]
|
|
11219
|
+
}
|
|
11099
11220
|
},
|
|
11100
11221
|
// DecisionProperties: Decision record. Strategic, product, engineering, or design.
|
|
11101
11222
|
decision: {
|
|
@@ -12128,7 +12249,7 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
12128
12249
|
},
|
|
12129
12250
|
// MessagingProperties: Messaging entity. Each instance is a channel/stage variant.
|
|
12130
12251
|
messaging: {
|
|
12131
|
-
channel: { type: "string", enum: ["landing_page", "email", "social", "ad", "pitch", "press", "in_product", "other"], description: "Channel this messaging variant is crafted for" },
|
|
12252
|
+
channel: { type: "string", enum: ["landing_page", "email", "social", "ad", "pitch", "press", "in_product", "enablement", "other"], description: "Channel this messaging variant is crafted for. `enablement` is the internal field-ops channel (SE/PMM/SA enablement one-pagers, battlecards' narrative), distinct from `pitch` (external, customer-facing)." },
|
|
12132
12253
|
funnel_stage: { type: "string", enum: ["awareness", "consideration", "conversion", "retention"], description: "Marketing funnel stage this variant targets" },
|
|
12133
12254
|
headline: { type: "string", description: "Primary headline or hook" },
|
|
12134
12255
|
body: { type: "string", description: "Full message body copy" },
|
|
@@ -23538,6 +23659,12 @@ var GTM_GUIDE = {
|
|
|
23538
23659
|
description: "Strategy defines positioning, positioning spawns messaging variants, messaging addresses objections with rebuttals backed by proof points",
|
|
23539
23660
|
entity_types: ["positioning", "messaging", "objection", "rebuttal", "proof_point"],
|
|
23540
23661
|
edge_chain: ["gtm_strategy_positions_via_positioning", "positioning_communicated_via_messaging", "positioning_challenged_by_objection", "objection_countered_by_rebuttal", "rebuttal_evidenced_by_proof_point"]
|
|
23662
|
+
},
|
|
23663
|
+
{
|
|
23664
|
+
name: "Audience Projection Lattice",
|
|
23665
|
+
description: "One feature approaching launch needs many faces: what the internal field org (SE/PMM/SA) needs to know differs from what an enterprise champion needs at beta versus GA. Model the atoms, not the rendered pages. A feature is communicated_via messaging variants; each variant targets a persona (an internal field-ops persona or a customer persona) and is used_in a staged launch (beta, then GA); the launch is coordinated_via a project (the readiness checklist: demo env, SE training, by when). The projection itself is a query over these atoms, rendered by the product, never a stored copy that drifts.",
|
|
23666
|
+
entity_types: ["feature", "messaging", "persona", "launch", "project"],
|
|
23667
|
+
edge_chain: ["feature_communicated_via_messaging", "messaging_targets_persona", "launch_ships_feature", "launch_coordinated_via_project"]
|
|
23541
23668
|
}
|
|
23542
23669
|
],
|
|
23543
23670
|
required_bridges: [
|
|
@@ -23583,17 +23710,33 @@ var SALES_GUIDE = {
|
|
|
23583
23710
|
description: "Pipelines qualify leads, leads become accounts, accounts negotiate deals that progress through pipeline stages and convert to subscriptions",
|
|
23584
23711
|
entity_types: ["pipeline_sales", "lead", "account", "deal", "pipeline_stage", "subscription"],
|
|
23585
23712
|
edge_chain: ["pipeline_sales_qualifies_lead", "lead_becomes_account", "account_negotiates_deal", "deal_at_pipeline_stage", "pipeline_sales_converts_to_subscription"]
|
|
23713
|
+
},
|
|
23714
|
+
{
|
|
23715
|
+
name: "Enterprise Buying Committee",
|
|
23716
|
+
description: "An enterprise deal is a months-long coordination effort, not a forecast row. Attach the decision-making unit directly to the deal (each contact carries a buying_role: champion, economic buyer, technical evaluator, procurement, detractor), then wire the gauntlet the deal must clear: objections it faces, the security review that gates it, and the contract it closes via. A deal with no champion and no economic buyer mapped is single-threaded and at risk.",
|
|
23717
|
+
entity_types: ["deal", "contact", "objection", "security_review", "contract"],
|
|
23718
|
+
edge_chain: ["account_negotiates_deal", "deal_involves_contact", "deal_challenged_by_objection", "deal_gated_by_security_review", "deal_closed_via_contract"]
|
|
23719
|
+
},
|
|
23720
|
+
{
|
|
23721
|
+
name: "Win/Loss Learning Loop",
|
|
23722
|
+
description: "Close the pre-sale learning loop the way the post-sale one already closes (support_ticket reveals need). A deal is armed with a competitive battlecard; when it is lost to a competitor, a win/loss research_study analyses it. This gives competitive_battle_card.win_rate a derivation path (nothing could compute it before) and turns lost deals into structured competitive intelligence rather than a note in a closed record.",
|
|
23723
|
+
entity_types: ["deal", "competitive_battle_card", "competitor", "research_study"],
|
|
23724
|
+
edge_chain: ["deal_armed_with_competitive_battle_card", "deal_lost_to_competitor", "research_study_analyzes_deal"]
|
|
23586
23725
|
}
|
|
23587
23726
|
],
|
|
23588
23727
|
required_bridges: [
|
|
23589
23728
|
{ edge_type: "lead_sourced_from_acquisition_channel", target_domain: "growth", when: "Track where leads come from for attribution" },
|
|
23590
23729
|
{ edge_type: "subscription_subscribes_to_pricing_tier", target_domain: "pricing", when: "Subscriptions should link to the tier purchased" },
|
|
23591
|
-
{ edge_type: "account_partners_via_partnership", target_domain: "business_model", when: "Partner accounts should link to the partnership entity" }
|
|
23730
|
+
{ edge_type: "account_partners_via_partnership", target_domain: "business_model", when: "Partner accounts should link to the partnership entity" },
|
|
23731
|
+
{ edge_type: "deal_blocked_by_feature", target_domain: "product_spec", when: 'When a roadmap gap holds up pipeline, link the deal to the blocking feature so "which features unblock how much revenue" is queryable' },
|
|
23732
|
+
{ edge_type: "account_implements_via_project", target_domain: "program_mgmt", when: "Post-sale onboarding/implementation reuses the program-management machinery (project/milestone/deliverable), scoped to the account" }
|
|
23592
23733
|
],
|
|
23593
23734
|
anti_patterns: [
|
|
23594
23735
|
{ description: "Deals without pipeline stages: every deal needs a current position in the pipeline" },
|
|
23595
23736
|
{ description: "Leads without source attribution. Attribution drives channel optimisation." },
|
|
23596
|
-
{ description: "Forecasts without probability: weight deals by likelihood to close" }
|
|
23737
|
+
{ description: "Forecasts without probability: weight deals by likelihood to close" },
|
|
23738
|
+
{ name: "Single-threaded enterprise deal", description: "An enterprise deal with no contacts attached (deal_involves_contact) or no champion/economic_buyer among their buying_role values is single-threaded: the whole relationship rests on one unmapped person. Attach the buying committee and map at least the champion and economic buyer.", affected_entity: "deal", remediation: "Create deal_involves_contact edges to the committee and set each contact's buying_role." },
|
|
23739
|
+
{ name: "Won/lost recorded only as a phase", description: "The deal outcome (won/lost/no_decision) is an Event-axis fact and belongs on deal_outcome, not conflated with the lifecycle status. A lost deal with no deal_lost_to_competitor edge also strands the competitive signal that competitive_battle_card.win_rate depends on.", affected_entity: "deal", remediation: "Set deal_outcome, and on a loss create deal_lost_to_competitor plus a win/loss research_study via research_study_analyzes_deal." }
|
|
23597
23740
|
]
|
|
23598
23741
|
};
|
|
23599
23742
|
var MARKETING_GUIDE = {
|
|
@@ -29982,7 +30125,7 @@ function isCanonical(text) {
|
|
|
29982
30125
|
}
|
|
29983
30126
|
|
|
29984
30127
|
// src/index.ts
|
|
29985
|
-
var UPG_VERSION = "0.
|
|
30128
|
+
var UPG_VERSION = "0.25.0";
|
|
29986
30129
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
29987
30130
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
29988
30131
|
var UPG_TYPES = getTypes();
|