@unified-product-graph/core 0.17.5 → 0.17.7

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/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
- 319 entity types across 37 domains. 1024 typed edges. 46 canonical framework definitions, with more added as each is reviewed.
10
+ 319 entity types across 37 domains. 1026 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
@@ -1386,7 +1386,13 @@ var UPG_EDGE_CATALOG = {
1386
1386
  research_study_collects_survey_response: { forward_verb: "collects", reverse_verb: "collected_in", classification: "hierarchy", source_type: "research_study", target_type: "survey_response" },
1387
1387
  observation_evidenced_by_quote: { forward_verb: "evidenced_by", reverse_verb: "evidences", classification: "hierarchy", source_type: "observation", target_type: "quote" },
1388
1388
  affinity_cluster_synthesises_insight: { forward_verb: "synthesises", reverse_verb: "synthesised_from", classification: "hierarchy", source_type: "affinity_cluster", target_type: "insight" },
1389
- insight_informs_opportunity: { forward_verb: "informs", reverse_verb: "informed_by", classification: "cross-domain", source_type: "insight", target_type: "opportunity" },
1389
+ // deliberate_only (0.17.6): "this insight informs that opportunity" is a
1390
+ // PM-judgment link — which of many opportunities a finding actually feeds is
1391
+ // authored, never inferred from a source's hierarchy. Auto-nest / adapter
1392
+ // parentage resolvers decline to materialise it (fall through to a
1393
+ // node_informs_node link or a decline+warn); explicit create_edge /
1394
+ // resolve_edge_for_pair still return it. Fixes the latent auto-emission.
1395
+ insight_informs_opportunity: { forward_verb: "informs", reverse_verb: "informed_by", classification: "cross-domain", source_type: "insight", target_type: "opportunity", deliberate_only: true },
1390
1396
  // 1.5 Market Intelligence Domain
1391
1397
  // product → competitive_analysis closes the parallel gap to
1392
1398
  // product → persona. competitive_analysis is the anchor of the
@@ -7064,6 +7070,8 @@ var PROPERTY_SCALE_MAP = {
7064
7070
  // validation/experiment_run
7065
7071
  bug_severity: "severity_5",
7066
7072
  // product-spec/bug (UPG-579 Option C collapse)
7073
+ magnitude: "severity_5",
7074
+ // user/switching_cost barrier size (0.17.7; restores the documented UPG-579 intent that a missing entry had silently overridden to scale_5)
7067
7075
  risk_level: "severity_5",
7068
7076
  // compliance/risk (UPG-579 Option B)
7069
7077
  scarcity_risk: "severity_5",
@@ -10751,8 +10759,6 @@ var UPG_PROPERTY_SCHEMA = {
10751
10759
  framework_id: { type: "string", description: "Framework ID (references `UPGFramework.id`)" },
10752
10760
  stage: { type: "string", enum: ["draft", "validated", "active"], description: "Maturity" },
10753
10761
  pattern: { type: "string", enum: ["freemium", "marketplace", "saas", "subscription", "transactional", "advertising", "licensing", "hybrid"], description: "Canonical pattern. Useful for benchmarking against peer businesses with the same shape." }
10754
- // monetisation_basis removed in 0.12.0 (P14 Bucket C) — categorical rollup of revenue_stream.billing_model.
10755
- // north_star_metric removed in 0.12.0 (P14) → `business_model_guided_by_metric` edge.
10756
10762
  },
10757
10763
  // CapabilityProperties: Capability entity.
10758
10764
  capability: {
@@ -10969,7 +10975,7 @@ var UPG_PROPERTY_SCHEMA = {
10969
10975
  // ConstraintProperties: Constraint: a named limitation or boundary on product creation.
10970
10976
  constraint: {
10971
10977
  constraint_kind: { type: "string", enum: ["resource", "technical", "regulatory", "temporal", "compliance", "other"], description: "Limitation category" },
10972
- constraint_origin: { type: "string", enum: ["internal", "external"], description: "Provenance: internal (a self-imposed principle or operating tenet) or external (a limit, requirement, or ceiling imposed from outside)." },
10978
+ constraint_origin: { type: "string", enum: ["internal", "external"], description: "Provenance: a self-imposed tenet (`internal`) or an imposed-on-us limit/requirement (`external`)." },
10973
10979
  constraint_status: { type: "string", enum: ["binding", "advisory", "lifted"], description: "Whether binding, advisory, or lifted" },
10974
10980
  rule_strength: { type: "string", enum: ["must", "must_not", "exception", "warning", "guideline"], description: "Enforcement strictness. Reuses the governance/guideline rule vocabulary." },
10975
10981
  source: { type: "string", description: "Free-text origin: policy document, regulation, stakeholder, technical doc." },
@@ -11586,7 +11592,7 @@ var UPG_PROPERTY_SCHEMA = {
11586
11592
  // FeatureFlagProperties: Feature flag.
11587
11593
  feature_flag: {
11588
11594
  key: { type: "string", description: 'Required. Stable flag key used in code (e.g. "new-checkout-flow").' },
11589
- rollout_pct: { type: "number", description: "Percentage enabled (0\u2013100). Meaningful when `flag_status === 'rollout'`.", modifier: "snapshot" },
11595
+ rollout_pct: { type: "number", description: "Percentage enabled (0\u2013100). Meaningful when the flag's `status === 'rollout'`.", modifier: "snapshot" },
11590
11596
  targeting_rules: { type: "string", description: "Human-readable targeting rules. Full rule evaluation happens in the flag service." },
11591
11597
  owner: { type: "string", description: "Owning person or team responsible for the flag's lifecycle. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
11592
11598
  flag_type: { type: "string", enum: ["temporary", "permanent", "experiment"], description: "Lifecycle classification. `temporary` = should be removed after rollout (kill switch, gradual rollout). `permanent` = long-lived feature gate (entitlement flag). `experiment` = A/B test with a defined end condition." },
@@ -12356,7 +12362,7 @@ var UPG_PROPERTY_SCHEMA = {
12356
12362
  is_highlighted: { type: "boolean", description: "Flagged as a highlight. Absorbed from the deprecated Highlight entity." },
12357
12363
  highlight_tag: { type: "string", description: 'Free-form highlight type tag. @example "pain", "delight", "behaviour", "moment of clarity"' },
12358
12364
  sentiment: { type: "string", enum: ["positive", "neutral", "negative", "mixed"], description: "Structured sentiment. Tools like Dovetail and EnjoyHQ converge on these four values. More precise than `highlight_tag` for aggregation." },
12359
- source_url: { type: "string", description: "Stable deep-link to the exact moment this observation was captured in the originating recording or transcript. A per-moment locator, not a study-level link. Distinct from `session_ref`, which holds an opaque session ID.", modifier: "volatile" }
12365
+ source_url: { type: "string", description: "Stable deep-link to the exact moment this observation was captured in the originating recording or transcript. A per-moment locator, not a study-level link. Distinct from `session_ref`, which holds an opaque session ID for AI inference. Rot-prone external pointer; treat as `volatile`.", modifier: "volatile" }
12360
12366
  },
12361
12367
  // OnCallRotationProperties: On-call rotation.
12362
12368
  on_call_rotation: {
@@ -12365,10 +12371,18 @@ var UPG_PROPERTY_SCHEMA = {
12365
12371
  rotation_cadence: { type: "string", enum: ["daily", "weekly", "biweekly", "custom"], description: "Cycle cadence. `weekly` for standard team rotations. `daily` for high-incident-volume teams." },
12366
12372
  handoff_time: { type: "string", description: 'Shift handoff time. Affects team coordination and sleep. @example "09:00 UTC", "17:00 local"' }
12367
12373
  },
12374
+ // OperatingLifecycleProperties: An operating_lifecycle: a canonical, ordered (often cyclic) operating process
12375
+ operating_lifecycle: {
12376
+ cyclic: { type: "boolean", description: "True if the process loops (e.g. Analyze \u2192 Extend \u2192 Plan). The sequence is fully expressed by the stages' `stage_order`; `cyclic` adds the wrap from the last stage back to the first." },
12377
+ source: { type: "string", description: 'Origin of the canonical model (e.g. "Sanity official content-ops lifecycle"). Optional provenance; promote to an edge if it names a real `specification`/`document`.' }
12378
+ },
12379
+ // OperatingStageProperties: An operating_stage: one ordered stage of an `operating_lifecycle`. A product's
12380
+ operating_stage: {
12381
+ stage_order: { type: "number", description: "Ordered position within the lifecycle, 0-indexed. The source of truth for sequence (pairs with `phase_order`/`step_order`/`action_order`)." },
12382
+ goal: { type: "string", description: "What this stage accomplishes." },
12383
+ owner_role: { type: "string", description: "Role that owns the stage (free-text role label). Optional; promote to a `node_owned_by_role` edge if ownership must be queryable across stages." }
12384
+ },
12368
12385
  // OpportunityProperties: A problem worth solving, grounded in user need and business value.
12369
- // No intrinsic scalar properties — defined by edges + framework-scoped scoring
12370
- // (reach/frequency/pain/opportunity_score live on the `opportunity-sizing`
12371
- // framework_exercise edge). Former props removed in 0.14.0 (UPG-574).
12372
12386
  opportunity: {},
12373
12387
  // OrganizationProperties: Organization entity.
12374
12388
  organization: {
@@ -12401,7 +12415,7 @@ var UPG_PROPERTY_SCHEMA = {
12401
12415
  alias: { type: "string", description: 'Anonymous alias for privacy (e.g. "P01")' },
12402
12416
  recruit_source: { type: "string", description: "How the participant was recruited" },
12403
12417
  consent_status: { type: "string", enum: ["pending", "given", "withdrawn"], description: "Current consent status for data usage" },
12404
- source_url: { type: "string", description: "Stable deep-link to the exact moment this participant appears in the originating recording or transcript. A per-moment locator, not a study-level link.", modifier: "volatile" }
12418
+ source_url: { type: "string", description: "Stable deep-link to the exact moment this participant appears in the originating recording or transcript. A per-moment locator, not a study-level link. Rot-prone external pointer; treat as `volatile`.", modifier: "volatile" }
12405
12419
  },
12406
12420
  // PartnerProgramProperties: Partner program.
12407
12421
  partner_program: {
@@ -12471,7 +12485,7 @@ var UPG_PROPERTY_SCHEMA = {
12471
12485
  tech_comfort: { type: "string", enum: ["low", "medium", "high", "expert", "other"], description: "Tech comfort. Closed set so personas across products compare on the same axis. Free-text colour belongs in `context` or `motivation`." },
12472
12486
  domain_expertise: { type: "string", description: 'Industry or domain knowledge this persona brings @example "10+ years SaaS experience", "New to healthcare IT"' },
12473
12487
  audience_role: { type: "string", enum: ["buyer", "user", "champion", "influencer", "partner"], description: 'Role in the buying / adoption decision (the decision-making-unit split): who signs (buyer) vs who uses (user) vs who advocates internally (champion) vs who shapes the choice (influencer) vs who delivers / implements (partner). A portfolio must separate the economic buyer from the practitioner user; they are distinct personas with distinct jobs. Closed set so roles compare across products. @example "buyer"' },
12474
- actor_kind: { type: "string", enum: ["human", "agent", "system"], description: "Who performs the work: a human archetype (default; absent = human, no migration), an autonomous AI agent (e.g. Content Agent), or a non-agentic platform service. An agent persona participates in journeys via the same persona machinery and is delegated to via persona_delegates_to_persona. Human-coverage / segmentation metrics count human only; agent/system opt-in." }
12488
+ actor_kind: { type: "string", enum: ["human", "agent", "system"], description: 'Who performs the work: a human archetype (default), an autonomous AI agent (e.g. Content Agent), or a non-agentic platform service. Absent = `human`, so existing personas need no migration. An `agent` persona is a first-class actor that participates in journeys via the same persona machinery and that humans delegate to via `persona_delegates_to_persona`. Human-coverage / segmentation metrics count `human` only; agent/system are opt-in. @example "agent"' }
12475
12489
  },
12476
12490
  // PipelineSalesProperties: Sales pipeline.
12477
12491
  pipeline_sales: {
@@ -12534,17 +12548,6 @@ var UPG_PROPERTY_SCHEMA = {
12534
12548
  defined_by: { type: "string", description: "The `specification/<slug>` this primitive comes from; nullable for spec-less internal primitives. Mirrors the `primitive_defined_by_specification` edge for quick lookup." },
12535
12549
  since: { type: "string", description: "Year or version the primitive was introduced." }
12536
12550
  },
12537
- // OperatingLifecycleProperties: a canonical ordered (often cyclic) operating process products' journey phases map onto.
12538
- operating_lifecycle: {
12539
- cyclic: { type: "boolean", description: "True if the process loops (e.g. Analyze \u2192 Extend \u2192 Plan). The sequence is expressed by the stages' stage_order; cyclic adds the wrap from last stage back to first." },
12540
- source: { type: "string", description: 'Origin of the canonical model (e.g. "Sanity official content-ops lifecycle"). Optional provenance; promote to an edge if it names a real specification/document.' }
12541
- },
12542
- // OperatingStageProperties: one ordered stage of an operating_lifecycle.
12543
- operating_stage: {
12544
- stage_order: { type: "number", description: "Ordered position within the lifecycle, 0-indexed. Source of truth for sequence." },
12545
- goal: { type: "string", description: "What this stage accomplishes." },
12546
- owner_role: { type: "string", description: "Role that owns the stage (free-text role label). Optional; promote to a node_owned_by_role edge if ownership must be queryable." }
12547
- },
12548
12551
  // PrivacyPolicyProperties: Privacy policy.
12549
12552
  privacy_policy: {
12550
12553
  version: { type: "string", description: "Version identifier of the policy" },
@@ -12625,7 +12628,7 @@ var UPG_PROPERTY_SCHEMA = {
12625
12628
  quote: {
12626
12629
  text: { type: "string", description: "Quoted text" },
12627
12630
  timestamp: { type: "string", description: "When said (ISO timestamp or session offset)" },
12628
- source_url: { type: "string", description: "Stable deep-link to the exact moment this quote was spoken in the originating recording or transcript. A per-moment locator, not a study-level link.", modifier: "volatile" }
12631
+ source_url: { type: "string", description: "Stable deep-link to the exact moment this quote was spoken in the originating recording or transcript. A per-moment locator, not a study-level link. Rot-prone external pointer; treat as `volatile`.", modifier: "volatile" }
12629
12632
  },
12630
12633
  // QuoteDocumentProperties: Quote document.
12631
12634
  quote_document: {
@@ -12654,7 +12657,7 @@ var UPG_PROPERTY_SCHEMA = {
12654
12657
  },
12655
12658
  required: ["value", "label"]
12656
12659
  },
12657
- evidence_refs: { type: "string[]", description: "References to supporting evidence" }
12660
+ evidence_refs: { type: "string[]", description: "References to supporting evidence (e.g. interview or observation ids)." }
12658
12661
  },
12659
12662
  // RegionalPricingProperties: Regional pricing.
12660
12663
  regional_pricing: {
@@ -12826,7 +12829,6 @@ var UPG_PROPERTY_SCHEMA = {
12826
12829
  cause_confidence: { type: "string", enum: ["hypothesised", "likely", "confirmed"], description: "Team certainty about this cause. `hypothesised` = educated guess. `likely` = evidence points here. `confirmed` = reproduced. Renamed from `confidence` in v0.4.0 to disambiguate from the entity-wide `UPGAssessment`-typed epistemic confidence used elsewhere. The 3-tier shape stays as a discrete RCA-lifecycle marker." },
12827
12830
  evidence_summary: { type: "string", description: "One-paragraph evidence summary. Log lines, traces, repro steps. Detailed artefacts go on linked `evidence` nodes." },
12828
12831
  affected_area: { type: "string", description: "Affected area of the system" }
12829
- // `category` (legacy, -> `cause_category`) and `verified` (= `cause_confidence === 'confirmed'`) removed in 0.14.0 (UPG-574).
12830
12832
  },
12831
12833
  // RunbookProperties: Runbook.
12832
12834
  runbook: {
@@ -12978,10 +12980,7 @@ var UPG_PROPERTY_SCHEMA = {
12978
12980
  post_type: { type: "string", enum: ["text", "image", "video", "carousel", "story"], description: "Format of the post" },
12979
12981
  scheduled_date: { type: "string", description: "Date the post is scheduled to publish (ISO format)" }
12980
12982
  },
12981
- // SolutionProperties: A proposed response to an opportunity.
12982
- // RICE scoring inputs (reach/impact/confidence/effort) + computed rice_score
12983
- // were framework-scoped from 0.9.0 and removed in 0.14.0 (UPG-574): they live
12984
- // on the `rice-scoring` framework_exercise edge, not the entity.
12983
+ // SolutionProperties: A proposed response to an opportunity
12985
12984
  solution: {
12986
12985
  timeline: { type: "string", description: "Estimated delivery or target timeline" }
12987
12986
  },
@@ -13040,18 +13039,14 @@ var UPG_PROPERTY_SCHEMA = {
13040
13039
  time_horizon: { type: "string", description: 'Standing / multi-year horizon, often open-ended (a pillar is durable). @example "3 years", "2026-2028", "ongoing"' },
13041
13040
  success_indicator: { type: "string", description: "How the business knows this durable pillar is on track. Narrative, not a metric edge. A strategic_theme deliberately has no success_indicator: it is measured through its child objectives, not on its own." }
13042
13041
  },
13043
- // StrategicQuestionProperties: StrategicQuestion entity. An open coordination or
13044
- // ownership question a plan is exposed to (strategy sibling of research_question /
13045
- // design_question). `status` is the node lifecycle (open -> resolved).
13042
+ // StrategicQuestionProperties: StrategicQuestion entity.
13046
13043
  strategic_question: {
13047
13044
  question: { type: "string", description: "The question itself. Primary content." },
13048
13045
  context: { type: "string", description: "Context that surfaced the question: the reorg, the boundary, the unowned area." },
13049
13046
  resolution: { type: "string", description: "The answer, captured when the question moves to `resolved`." },
13050
13047
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Importance to resolve relative to other open questions." }
13051
13048
  },
13052
- // StrategicThemeProperties: StrategicTheme entity. A time-bound thrust WITHIN a
13053
- // strategic_pillar (distinct cascade level, UPG-692 T3.3) — measured through its
13054
- // child objectives, so it carries no success_indicator of its own.
13049
+ // StrategicThemeProperties: StrategicTheme entity.
13055
13050
  strategic_theme: {
13056
13051
  owner: { type: "string", description: "Owning person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
13057
13052
  time_horizon: { type: "string", description: 'Bounded period this theme is active (a theme is time-bound, within a pillar). @example "Q1 2026", "FY26"' },
@@ -13104,7 +13099,7 @@ var UPG_PROPERTY_SCHEMA = {
13104
13099
  magnitude: {
13105
13100
  type: "assessment",
13106
13101
  scale_id: "severity_5",
13107
- description: "How large the switching barrier is (UPGAssessment on the `severity_5` scale). Steered onto the canonical scale to match sibling assessments. Migrated from the `high | medium | low` enum (UPG-579 Option C): map `high` -> 4, `medium` -> 3, `low` -> 2; carry the old word in `label`.",
13102
+ description: "How large the barrier is (UPGAssessment on the `severity_5` scale).",
13108
13103
  properties: {
13109
13104
  value: { type: "number", description: "The numeric value, used for computation." },
13110
13105
  label: { type: "string", description: "The qualitative label (what the assessor meant)." },
@@ -13151,7 +13146,6 @@ var UPG_PROPERTY_SCHEMA = {
13151
13146
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Relative importance against other tasks" },
13152
13147
  due_date: { type: "string", description: "ISO date due. Typically bounded by the containing story's due date." },
13153
13148
  labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." }
13154
- // `estimate` (story_task collapse relic, duplicated `effort`) removed in 0.14.0 (UPG-574).
13155
13149
  },
13156
13150
  // TeamProperties: Team entity.
13157
13151
  team: {
@@ -13300,7 +13294,7 @@ var UPG_PROPERTY_SCHEMA = {
13300
13294
  methodology: { type: "string", enum: ["stride", "dread", "pasta", "attack_tree", "other"], description: 'Methodology. `stride` = Spoofing, Tampering, Repudiation, Information Disclosure, DoS, Elevation of Privilege (OWASP standard). `dread` = Damage, Reproducibility, Exploitability, Affected users, Discoverability (numeric scoring). `pasta` = Process for Attack Simulation and Threat Analysis (7-stage). `attack_tree` = hierarchical tree of attack paths. @example "stride" is the most widely used methodology for web applications' },
13301
13295
  scope: { type: "string", description: 'What system, feature, or data flow is being analysed. @example "user authentication", "payment processing", "admin API"' },
13302
13296
  last_reviewed: { type: "string", description: 'ISO date last reviewed. Models become stale as systems evolve. @example "2026-03-01"' },
13303
- participants: { type: "string", description: 'Participants in the exercise. @example "Alice Chen (security lead), Bob Park (backend engineer), Carol Liu (architect)". Promote individuals to `node_owned_by_person` edges if participation must be queryable.' },
13297
+ participants: { type: "string", description: 'Participants in the exercise. Promote individuals to `node_owned_by_person` edges if participation must be queryable. @example "Alice Chen (security lead), Bob Park (backend engineer), Carol Liu (architect)"' },
13304
13298
  threat_count: { type: "number", description: "Threats identified. Key metric for scope and completeness. @example 12", modifier: "derived" }
13305
13299
  },
13306
13300
  // TouchpointProperties: Customer touchpoint.
@@ -13395,7 +13389,7 @@ var UPG_PROPERTY_SCHEMA = {
13395
13389
  // VisionProperties: Vision entity.
13396
13390
  vision: {
13397
13391
  timeframe: { type: "string", description: 'Target timeframe. @example "3 years"' },
13398
- north_star: { type: "string", description: "Single north-star metric or statement" },
13392
+ north_star: { type: "string", description: "The north-star statement: a prose slogan of the future the product steers toward. Legitimately free-text (graph-vs-prose). To link the *metric* a vision optimises for, use the `vision_anchored_by_metric` edge (P14 0.12.0)." },
13399
13393
  success_looks_like: { type: "string", description: "Narrative of what success looks like" }
13400
13394
  },
13401
13395
  // VulnerabilityProperties: Vulnerability.
@@ -29981,7 +29975,7 @@ function isCanonical(text) {
29981
29975
  }
29982
29976
 
29983
29977
  // src/index.ts
29984
- var UPG_VERSION = "0.17.5";
29978
+ var UPG_VERSION = "0.17.7";
29985
29979
  var UPG_FORMAT_VERSION = "0.4.0";
29986
29980
  var MARKDOWN_FORMAT_VERSION = "0.1";
29987
29981
  var UPG_TYPES = getTypes();