@unified-product-graph/core 0.12.3 → 0.12.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.js CHANGED
@@ -8428,6 +8428,288 @@ var UPG_SCALAR_TO_EDGE_MIGRATIONS = {
8428
8428
  drop_scalar: true,
8429
8429
  reason: "P14 shadow: the subscription_subscribes_to_pricing_tier edge already exists. Backfill the plan as a pricing_tier edge, then drop the name string."
8430
8430
  }
8431
+ ],
8432
+ "0.12.4": [
8433
+ // ── Bucket B — actor-as-string (ADDITIVE: add the ownership edge, KEEP the display string) ──
8434
+ // Per the scalar-vs-edge ADR display-cache rule (2026-06-16) and T3.1 (reuse the
8435
+ // polymorphic node_owned_by_* family; do NOT mint typed actor edges). `drop_scalar`
8436
+ // is FALSE for every entry: the string stays as a human-readable display-cache, and
8437
+ // the edge makes "everything owned by X" queryable across instances. OPT-IN — consumers
8438
+ // run promote_scalars_to_edges when they want the edges; nothing is forced on upgrade.
8439
+ // person-vs-team is the field-level call (ratified 2026-06-16): org units + durable
8440
+ // platform/components → team (9); work items, authored artifacts, and DRIs → person.
8441
+ // Two single-string participant fields (threat_model.participants, ceremony.participants)
8442
+ // are intentionally NOT here: a free-text name list cannot be promoted to one edge
8443
+ // without guessing — they are re-doc'd as display-cache only.
8444
+ // ── owned by a team (org units + durable platform/components) ──
8445
+ {
8446
+ from_type: "feature_area",
8447
+ scalar_property: "owner",
8448
+ target_type: "team",
8449
+ edge_type: "node_owned_by_team",
8450
+ drop_scalar: false,
8451
+ reason: 'P14 actor: a feature area is owned by a team; link node_owned_by_team so "everything this team owns" is queryable. Display string kept as a cache.'
8452
+ },
8453
+ {
8454
+ from_type: "bounded_context",
8455
+ scalar_property: "team_owner",
8456
+ target_type: "team",
8457
+ edge_type: "node_owned_by_team",
8458
+ drop_scalar: false,
8459
+ reason: "P14 actor: the owning team is a first-class entity; link node_owned_by_team. Display string kept as a cache."
8460
+ },
8461
+ {
8462
+ from_type: "service",
8463
+ scalar_property: "owner",
8464
+ target_type: "team",
8465
+ edge_type: "node_owned_by_team",
8466
+ drop_scalar: false,
8467
+ reason: "P14 actor: Backstage-style service ownership rolls up by team; link node_owned_by_team. Display string kept as a cache."
8468
+ },
8469
+ {
8470
+ from_type: "product_area",
8471
+ scalar_property: "owner",
8472
+ target_type: "team",
8473
+ edge_type: "node_owned_by_team",
8474
+ drop_scalar: false,
8475
+ reason: "P14 actor: a product area is an org unit owned by a team; link node_owned_by_team. Display string kept as a cache."
8476
+ },
8477
+ {
8478
+ from_type: "api_contract",
8479
+ scalar_property: "owner",
8480
+ target_type: "team",
8481
+ edge_type: "node_owned_by_team",
8482
+ drop_scalar: false,
8483
+ reason: "P14 actor: an API contract is a service-interface component owned by the team that owns the service (Backstage); link node_owned_by_team. Display string kept as a cache."
8484
+ },
8485
+ {
8486
+ from_type: "database_schema",
8487
+ scalar_property: "owner",
8488
+ target_type: "team",
8489
+ edge_type: "node_owned_by_team",
8490
+ drop_scalar: false,
8491
+ reason: "P14 actor: a database schema is a data component owned by the team responsible for it; link node_owned_by_team. Display string kept as a cache."
8492
+ },
8493
+ {
8494
+ from_type: "design_system",
8495
+ scalar_property: "maintainer",
8496
+ target_type: "team",
8497
+ edge_type: "node_owned_by_team",
8498
+ drop_scalar: false,
8499
+ reason: "P14 actor: a design system is a shared platform maintained by a team; link node_owned_by_team. Display string kept as a cache."
8500
+ },
8501
+ {
8502
+ from_type: "service_level_agreement",
8503
+ scalar_property: "owner",
8504
+ target_type: "team",
8505
+ edge_type: "node_owned_by_team",
8506
+ drop_scalar: false,
8507
+ reason: "P14 actor: an SLA is a service-provider-side commitment owned by a team; link node_owned_by_team. Display string kept as a cache."
8508
+ },
8509
+ {
8510
+ from_type: "key_activity",
8511
+ scalar_property: "operational_owner",
8512
+ target_type: "team",
8513
+ edge_type: "node_owned_by_team",
8514
+ drop_scalar: false,
8515
+ reason: "P14 actor: the operationally accountable owner of a recurring activity is a team; link node_owned_by_team. Display string kept as a cache."
8516
+ },
8517
+ // ── owned by a person (DRIs, work items, authored artifacts; the string is a name, handle, or email) ──
8518
+ {
8519
+ from_type: "strategic_theme",
8520
+ scalar_property: "owner",
8521
+ target_type: "person",
8522
+ edge_type: "node_owned_by_person",
8523
+ drop_scalar: false,
8524
+ reason: "P14 actor: the theme owner is a first-class person; link node_owned_by_person so cross-theme ownership is queryable. Display string kept."
8525
+ },
8526
+ {
8527
+ from_type: "initiative",
8528
+ scalar_property: "owner",
8529
+ target_type: "person",
8530
+ edge_type: "node_owned_by_person",
8531
+ drop_scalar: false,
8532
+ reason: "P14 actor: the initiative owner is a first-class person; link node_owned_by_person. Display string kept."
8533
+ },
8534
+ {
8535
+ from_type: "strategic_pillar",
8536
+ scalar_property: "owner",
8537
+ target_type: "person",
8538
+ edge_type: "node_owned_by_person",
8539
+ drop_scalar: false,
8540
+ reason: "P14 actor: the pillar owner is a first-class person; link node_owned_by_person. Display string kept."
8541
+ },
8542
+ {
8543
+ from_type: "metric",
8544
+ scalar_property: "owner",
8545
+ target_type: "person",
8546
+ edge_type: "node_owned_by_person",
8547
+ drop_scalar: false,
8548
+ reason: 'P14 actor: the metric owner is a first-class person ("every metric this person owns"); link node_owned_by_person. Display string kept.'
8549
+ },
8550
+ {
8551
+ from_type: "data_domain",
8552
+ scalar_property: "steward",
8553
+ target_type: "person",
8554
+ edge_type: "node_owned_by_person",
8555
+ drop_scalar: false,
8556
+ reason: "P14 actor: the data steward is a first-class person; link node_owned_by_person. Display string kept."
8557
+ },
8558
+ {
8559
+ from_type: "partnership",
8560
+ scalar_property: "owner",
8561
+ target_type: "person",
8562
+ edge_type: "node_owned_by_person",
8563
+ drop_scalar: false,
8564
+ reason: "P14 actor: the partnership owner is a first-class person; link node_owned_by_person. Display string kept."
8565
+ },
8566
+ {
8567
+ from_type: "key_resource",
8568
+ scalar_property: "owner",
8569
+ target_type: "person",
8570
+ edge_type: "node_owned_by_person",
8571
+ drop_scalar: false,
8572
+ reason: "P14 actor: the resource owner is a first-class person; link node_owned_by_person. Display string kept."
8573
+ },
8574
+ {
8575
+ from_type: "document",
8576
+ scalar_property: "author",
8577
+ target_type: "person",
8578
+ edge_type: "node_owned_by_person",
8579
+ drop_scalar: false,
8580
+ reason: 'P14 actor: the author is a first-class person ("every document by this author"); link node_owned_by_person. Display string kept.'
8581
+ },
8582
+ {
8583
+ from_type: "outcome",
8584
+ scalar_property: "owner",
8585
+ target_type: "person",
8586
+ edge_type: "node_owned_by_person",
8587
+ drop_scalar: false,
8588
+ reason: "P14 actor: the outcome owner is a first-class person; link node_owned_by_person. Display string kept."
8589
+ },
8590
+ {
8591
+ from_type: "feature",
8592
+ scalar_property: "owner",
8593
+ target_type: "person",
8594
+ edge_type: "node_owned_by_person",
8595
+ drop_scalar: false,
8596
+ reason: "P14 actor: the feature owner is a first-class person; link node_owned_by_person. Display string kept."
8597
+ },
8598
+ {
8599
+ from_type: "epic",
8600
+ scalar_property: "owner",
8601
+ target_type: "person",
8602
+ edge_type: "node_owned_by_person",
8603
+ drop_scalar: false,
8604
+ reason: "P14 actor: the epic owner is a first-class person; link node_owned_by_person. Display string kept."
8605
+ },
8606
+ {
8607
+ from_type: "release",
8608
+ scalar_property: "owner",
8609
+ target_type: "person",
8610
+ edge_type: "node_owned_by_person",
8611
+ drop_scalar: false,
8612
+ reason: "P14 actor: the release owner is a first-class person; link node_owned_by_person. Display string kept."
8613
+ },
8614
+ {
8615
+ from_type: "task",
8616
+ scalar_property: "assignee",
8617
+ target_type: "person",
8618
+ edge_type: "node_owned_by_person",
8619
+ drop_scalar: false,
8620
+ reason: 'P14 actor: the assignee is a first-class person ("every task assigned to this person"); link node_owned_by_person. Display string kept.'
8621
+ },
8622
+ {
8623
+ from_type: "bug",
8624
+ scalar_property: "assignee",
8625
+ target_type: "person",
8626
+ edge_type: "node_owned_by_person",
8627
+ drop_scalar: false,
8628
+ reason: "P14 actor: the assignee is a first-class person; link node_owned_by_person. Display string kept."
8629
+ },
8630
+ {
8631
+ from_type: "roadmap",
8632
+ scalar_property: "owner",
8633
+ target_type: "person",
8634
+ edge_type: "node_owned_by_person",
8635
+ drop_scalar: false,
8636
+ reason: "P14 actor: the roadmap owner is a first-class person; link node_owned_by_person. Display string kept."
8637
+ },
8638
+ {
8639
+ from_type: "journey_step",
8640
+ scalar_property: "owner",
8641
+ target_type: "person",
8642
+ edge_type: "node_owned_by_person",
8643
+ drop_scalar: false,
8644
+ reason: "P14 actor: the journey-step owner is a first-class person; link node_owned_by_person. Display string kept."
8645
+ },
8646
+ {
8647
+ from_type: "design_concept",
8648
+ scalar_property: "owner",
8649
+ target_type: "person",
8650
+ edge_type: "node_owned_by_person",
8651
+ drop_scalar: false,
8652
+ reason: "P14 actor: the design-concept owner is a first-class person; link node_owned_by_person. Display string kept."
8653
+ },
8654
+ {
8655
+ from_type: "technical_debt_item",
8656
+ scalar_property: "owner",
8657
+ target_type: "person",
8658
+ edge_type: "node_owned_by_person",
8659
+ drop_scalar: false,
8660
+ reason: "P14 actor: the debt-item owner is a first-class person; link node_owned_by_person. Display string kept."
8661
+ },
8662
+ {
8663
+ from_type: "feature_flag",
8664
+ scalar_property: "owner",
8665
+ target_type: "person",
8666
+ edge_type: "node_owned_by_person",
8667
+ drop_scalar: false,
8668
+ reason: "P14 actor: the flag owner is a first-class person; link node_owned_by_person. Display string kept."
8669
+ },
8670
+ {
8671
+ from_type: "deployment",
8672
+ scalar_property: "deployer",
8673
+ target_type: "person",
8674
+ edge_type: "node_owned_by_person",
8675
+ drop_scalar: false,
8676
+ reason: 'P14 actor: the deployer is a first-class person ("every deployment by this person"); link node_owned_by_person. Display string kept.'
8677
+ },
8678
+ {
8679
+ from_type: "investigation",
8680
+ scalar_property: "lead_investigator",
8681
+ target_type: "person",
8682
+ edge_type: "node_owned_by_person",
8683
+ drop_scalar: false,
8684
+ reason: "P14 actor: the lead investigator is a first-class person; link node_owned_by_person. Display string kept."
8685
+ },
8686
+ {
8687
+ from_type: "department",
8688
+ scalar_property: "leader",
8689
+ target_type: "person",
8690
+ edge_type: "node_owned_by_person",
8691
+ drop_scalar: false,
8692
+ reason: "P14 actor: the department leader is a first-class person; link node_owned_by_person. Display string kept."
8693
+ },
8694
+ // ── owned by people (multi: string[] of names) ──
8695
+ {
8696
+ from_type: "decision",
8697
+ scalar_property: "decision_makers",
8698
+ target_type: "person",
8699
+ edge_type: "node_owned_by_person",
8700
+ multi: true,
8701
+ drop_scalar: false,
8702
+ reason: "P14 actor: each decision-maker is a first-class person; one node_owned_by_person edge per name. Display list kept as a cache."
8703
+ },
8704
+ {
8705
+ from_type: "review_gate",
8706
+ scalar_property: "required_approvers",
8707
+ target_type: "person",
8708
+ edge_type: "node_owned_by_person",
8709
+ multi: true,
8710
+ drop_scalar: false,
8711
+ reason: "P14 actor: each required approver is a first-class person; one node_owned_by_person edge per name. Display list kept as a cache."
8712
+ }
8431
8713
  ]
8432
8714
  };
8433
8715
  function getScalarToEdgeMigrations(fromVersion, toVersion) {
@@ -9679,7 +9961,7 @@ var UPG_PROPERTY_SCHEMA = {
9679
9961
  spec_url: { type: "string", description: "URL of the specification document" },
9680
9962
  protocol: { type: "string", enum: ["REST", "GraphQL", "gRPC", "AsyncAPI", "SOAP", "WebSocket", "MQTT", "SSE", "other"], description: "Communication protocol. `SSE` (server-sent events) added in 0.9.12." },
9681
9963
  version: { type: "string", description: "API version" },
9682
- owner: { type: "string", description: "Maintaining person or team." }
9964
+ owner: { type: "string", description: "Maintaining person or team. Promote to a `node_owned_by_team` edge if ownership must be queryable." }
9683
9965
  },
9684
9966
  // ApiEcosystemProperties: API ecosystem.
9685
9967
  api_ecosystem: {
@@ -9760,7 +10042,7 @@ var UPG_PROPERTY_SCHEMA = {
9760
10042
  },
9761
10043
  // BoundedContextProperties: DDD bounded context.
9762
10044
  bounded_context: {
9763
- team_owner: { type: "string", description: "Owning team" },
10045
+ team_owner: { type: "string", description: "Owning team. Promote to a `node_owned_by_team` edge if ownership must be queryable." },
9764
10046
  tech_stack: { type: "string[]", description: "Technologies used within this context" },
9765
10047
  ubiquitous_language: { type: "string", description: "Key terms and their definitions" }
9766
10048
  },
@@ -9849,7 +10131,7 @@ var UPG_PROPERTY_SCHEMA = {
9849
10131
  steps_to_reproduce: { type: "string", description: "Step-by-step reproduction" },
9850
10132
  environment: { type: "string", description: 'Observed environment (e.g. "prod", "staging", "iOS 17.4")' },
9851
10133
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Urgency relative to other work. Independent of `bug_severity` (a critical bug can have low priority if rare)." },
9852
- assignee: { type: "string", description: "Assigned person" },
10134
+ assignee: { type: "string", description: "Assigned person. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
9853
10135
  due_date: { type: "string", description: "ISO date due. Often tied to a release gate or SLA." },
9854
10136
  labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." }
9855
10137
  },
@@ -9889,7 +10171,7 @@ var UPG_PROPERTY_SCHEMA = {
9889
10171
  ceremony_type: { type: "string", enum: ["standup", "planning", "review", "retro", "sync", "demo", "other"], description: "Kind of recurring meeting" },
9890
10172
  cadence: { type: "string", enum: ["continuous", "hourly", "daily", "weekly", "monthly", "quarterly", "yearly", "on_demand", "other"], description: "How often the ceremony occurs. Uses the shared `Cadence` scale." },
9891
10173
  duration_minutes: { type: "number", description: "Typical duration of the meeting in minutes" },
9892
- participants: { type: "string", description: "People or roles who attend" }
10174
+ participants: { type: "string", description: "People or roles who attend. Promote individuals to `node_owned_by_person` edges if participation must be queryable." }
9893
10175
  },
9894
10176
  // CertificationProperties: Certification.
9895
10177
  certification: {
@@ -10219,7 +10501,7 @@ var UPG_PROPERTY_SCHEMA = {
10219
10501
  },
10220
10502
  // DataDomainProperties: DataDomain. A coarse-grained grouping of related data assets (sources,
10221
10503
  data_domain: {
10222
- steward: { type: "string", description: "Accountable person or team" },
10504
+ steward: { type: "string", description: "Accountable person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
10223
10505
  domain_type: { type: "string", enum: ["master", "operational", "analytical", "reference"], description: "Domain contents classification. `master` = canonical entity data (customers, products). `operational` = live transactional data. `analytical` = warehouse / BI data. `reference` = slow-changing lookup data." },
10224
10506
  sensitivity: { type: "string", enum: ["public", "internal", "confidential", "restricted"], description: "Sensitivity band applied across the domain" }
10225
10507
  },
@@ -10285,7 +10567,7 @@ var UPG_PROPERTY_SCHEMA = {
10285
10567
  db_type: { type: "string", enum: ["postgres", "mysql", "mongodb", "redis", "other"], description: "Engine" },
10286
10568
  schema_version: { type: "string", description: "Current schema version" },
10287
10569
  migration_status: { type: "string", enum: ["current", "pending", "failed"], description: "Pending-migration status" },
10288
- owner: { type: "string", description: "Owning person or team responsible for design and migrations." },
10570
+ owner: { type: "string", description: "Owning person or team responsible for design and migrations. Promote to a `node_owned_by_team` edge if ownership must be queryable." },
10289
10571
  table_count: { type: "number", description: "Tables or collections in this schema. Useful for migration scope estimation." }
10290
10572
  },
10291
10573
  // DealProperties: Deal.
@@ -10303,7 +10585,7 @@ var UPG_PROPERTY_SCHEMA = {
10303
10585
  date: { type: "string", description: "ISO date the decision was made or last meaningfully updated." },
10304
10586
  decision_outcome: { type: "string", description: "Outcome text. What was decided. Separate from `rationale` (which explains why)." },
10305
10587
  consequences: { type: "string", description: `Known positive and negative consequences. Mirrors MADR's "Consequences" section.` },
10306
- decision_makers: { type: "string[]", description: `People who made the decision. Mirrors MADR's "Deciders" field.` },
10588
+ decision_makers: { type: "string[]", description: 'People who made the decision. Mirrors MADR\'s "Deciders" field. Promote to `node_owned_by_person` edges (one per name) if ownership must be queryable.' },
10307
10589
  decision_drivers: { type: "string[]", description: `Forces, constraints, and goals that shaped the decision. Mirrors MADR's "Decision Drivers" section. @example ["must work offline", "team has no Go expertise", "cost < $500/mo"]` }
10308
10590
  },
10309
10591
  // DeliverableProperties: Deliverable.
@@ -10324,7 +10606,7 @@ var UPG_PROPERTY_SCHEMA = {
10324
10606
  headcount: { type: "number", description: "Total number of people in the department" },
10325
10607
  budget: { type: "number", description: "Annual budget allocated to the department" },
10326
10608
  department_mission: { type: "string", description: "Charter / purpose statement for the department" },
10327
- leader: { type: "string", description: "Department leader (person or role reference)" },
10609
+ leader: { type: "string", description: "Department leader (person or role reference). Promote to a `node_owned_by_person` edge if ownership must be queryable." },
10328
10610
  fiscal_year: { type: "string", description: "Fiscal year the headcount / budget numbers apply to" }
10329
10611
  },
10330
10612
  // DependencyProperties: Dependency entity.
@@ -10342,7 +10624,7 @@ var UPG_PROPERTY_SCHEMA = {
10342
10624
  deploy_status: { type: "string", enum: ["success", "failure", "rolling"], description: "Current status" },
10343
10625
  sha: { type: "string", description: "Git SHA of the deployed commit" },
10344
10626
  duration_seconds: { type: "number", description: "Wall-clock duration in seconds. Tracks deployment speed trends." },
10345
- deployer: { type: "string", description: "Triggering person or system." }
10627
+ deployer: { type: "string", description: "Triggering person or system. Promote to a `node_owned_by_person` edge if ownership must be queryable." }
10346
10628
  },
10347
10629
  // DesignComponentProperties: Design system component.
10348
10630
  design_component: {
@@ -10359,7 +10641,7 @@ var UPG_PROPERTY_SCHEMA = {
10359
10641
  rationale: { type: "string", description: "Selection or rejection rationale" },
10360
10642
  concept_status: { type: "string", enum: ["exploring", "validated", "selected", "rejected"], description: "Current selection status" },
10361
10643
  maturity: { type: "string", enum: ["sketch", "refined", "final"], description: "Development stage, from rough idea to presentation-ready" },
10362
- owner: { type: "string", description: "Shepherding designer or researcher" }
10644
+ owner: { type: "string", description: "Shepherding designer or researcher. Promote to a `node_owned_by_person` edge if ownership must be queryable." }
10363
10645
  },
10364
10646
  // DesignGuidelineProperties: Design guideline.
10365
10647
  design_guideline: {
@@ -10410,7 +10692,7 @@ var UPG_PROPERTY_SCHEMA = {
10410
10692
  design_system: {
10411
10693
  version: { type: "string", description: "Current version" },
10412
10694
  repo_path: { type: "string", description: "Code repository or package path" },
10413
- maintainer: { type: "string", description: "Maintaining person or team" },
10695
+ maintainer: { type: "string", description: "Maintaining person or team. Promote to a `node_owned_by_team` edge if ownership must be queryable." },
10414
10696
  license: { type: "string", description: "Open-source license, if public" },
10415
10697
  homepage_url: { type: "string", description: "Documentation homepage. Public-facing entry point." }
10416
10698
  },
@@ -10473,7 +10755,7 @@ var UPG_PROPERTY_SCHEMA = {
10473
10755
  source_url: { type: "string", description: "Canonical retrievable URL" },
10474
10756
  platform: { type: "string", enum: ["markdown", "notion", "figma", "google_docs", "confluence", "github", "linear", "other"], description: "Hosting platform" },
10475
10757
  document_type: { type: "string", enum: ["vision", "plan", "decision", "research", "spec", "audit", "session", "feedback", "case-study", "narrative", "bug-report", "archive-collection", "rfc", "runbook", "guide", "onboarding", "brief", "report", "reference"], description: "Purpose classification" },
10476
- author: { type: "string", description: "Author (free-form: name, email, or handle)" },
10758
+ author: { type: "string", description: "Author (free-form: name, email, or handle). Promote to a `node_owned_by_person` edge if ownership must be queryable." },
10477
10759
  last_updated: { type: "string", description: "ISO 8601 last-meaningful-update" },
10478
10760
  word_count: { type: "number", description: "Approximate word count. Useful for planning, indexing, summarisation." },
10479
10761
  content_summary: { type: "string", description: "1\u20133 sentence summary. Drives previews, search snippets, embedding context." },
@@ -10511,7 +10793,7 @@ var UPG_PROPERTY_SCHEMA = {
10511
10793
  epic: {
10512
10794
  estimate: { type: "string", description: 'Rough size estimate (e.g. "3 sprints", "L", "13 points")' },
10513
10795
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Task-level priority" },
10514
- owner: { type: "string", description: "Responsible person or team" },
10796
+ owner: { type: "string", description: "Responsible person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
10515
10797
  start_date: { type: "string", description: "ISO date work begins" },
10516
10798
  target_date: { type: "string", description: "ISO date work completes" }
10517
10799
  },
@@ -10691,7 +10973,7 @@ var UPG_PROPERTY_SCHEMA = {
10691
10973
  // FeatureProperties: A discrete, user-facing capability of the product.
10692
10974
  feature: {
10693
10975
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Task-level priority" },
10694
- owner: { type: "string", description: "Responsible person or team" },
10976
+ owner: { type: "string", description: "Responsible person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
10695
10977
  start_date: { type: "string", description: "ISO date work begins" },
10696
10978
  target_date: { type: "string", description: "ISO date work completes" },
10697
10979
  health: { type: "string", enum: ["on_track", "at_risk", "off_track"], description: "Delivery health" }
@@ -10701,7 +10983,7 @@ var UPG_PROPERTY_SCHEMA = {
10701
10983
  scope_summary: { type: "string", description: "One-line scope description. Disambiguates from sibling areas at a glance." },
10702
10984
  owning_team: { type: "string", description: "Team identifier or slug. Free-form display. Canonical relationship is the `team_owns_feature_area` edge." },
10703
10985
  feature_count: { type: "number", description: "Approximate feature count under this area. Snapshot; `feature_area_contains_feature` edges are the source of truth.", modifier: "derived" },
10704
- owner: { type: "string", description: "Area owner (handle or email)" },
10986
+ owner: { type: "string", description: "Area owner (handle or email). Promote to a `node_owned_by_team` edge if ownership must be queryable." },
10705
10987
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Importance to the product overall" },
10706
10988
  maturity: { type: "string", enum: ["nascent", "growing", "mature", "legacy"], description: "Maturity. `nascent` = newly-formed grouping. `mature` = established surface. `legacy` = being phased out for a successor." },
10707
10989
  area_status: { type: "string", enum: ["active", "planned", "deprecated"], description: "Status in the product structure" }
@@ -10712,7 +10994,7 @@ var UPG_PROPERTY_SCHEMA = {
10712
10994
  flag_status: { type: "string", enum: ["on", "off", "rollout"], description: "Activation state. `on` = enabled for all. `off` = disabled for all. `rollout` = partial via targeting_rules." },
10713
10995
  rollout_pct: { type: "number", description: "Percentage enabled (0\u2013100). Meaningful when `flag_status === 'rollout'`." },
10714
10996
  targeting_rules: { type: "string", description: "Human-readable targeting rules. Full rule evaluation happens in the flag service." },
10715
- owner: { type: "string", description: "Owning person or team responsible for the flag's lifecycle." },
10997
+ 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." },
10716
10998
  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." },
10717
10999
  expiry_date: { type: "string", description: "ISO date after which this flag should be cleaned up. A temporary flag without an `expiry_date` is a code smell." },
10718
11000
  created_date: { type: "string", description: "Creation date. Useful for flag age and stale-flag detection." }
@@ -10951,7 +11233,7 @@ var UPG_PROPERTY_SCHEMA = {
10951
11233
  start_date: { type: "string", description: 'ISO start date. @example "2026-04-01"' },
10952
11234
  end_date: { type: "string", description: 'ISO end date. @example "2026-09-30"' },
10953
11235
  budget: { type: "number", description: "Budget allocated (base currency units)" },
10954
- owner: { type: "string", description: "Owning person or team" }
11236
+ owner: { type: "string", description: "Owning person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." }
10955
11237
  },
10956
11238
  // InsightProperties: Unified insight, synthesised from evidence and observations.
10957
11239
  insight: {
@@ -11020,7 +11302,7 @@ var UPG_PROPERTY_SCHEMA = {
11020
11302
  findings: { type: "string", description: "Findings discovered so far" },
11021
11303
  started_at: { type: "string", description: "ISO timestamp the investigation began" },
11022
11304
  resolved_at: { type: "string", description: "ISO timestamp the investigation was concluded. Pairs with `status === 'resolved' | 'abandoned'`." },
11023
- lead_investigator: { type: "string", description: "Lead investigator (email or handle). Distinct from the team owning the affected service." },
11305
+ lead_investigator: { type: "string", description: "Lead investigator (email or handle). Distinct from the team owning the affected service. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
11024
11306
  session_id: { type: "string", description: "Originating session" },
11025
11307
  category: { type: "string", enum: ["performance", "security", "data_quality", "reliability", "cost", "compliance", "other"], description: "Kind of issue under investigation. Distinct from `RootCauseProperties.cause_category`, which captures *why something went wrong*." }
11026
11308
  },
@@ -11150,7 +11432,7 @@ var UPG_PROPERTY_SCHEMA = {
11150
11432
  required: ["value", "label"]
11151
11433
  },
11152
11434
  thought: { type: "string", description: "What the user is thinking" },
11153
- owner: { type: "string", description: "Responsible owner" }
11435
+ owner: { type: "string", description: "Responsible owner. Promote to a `node_owned_by_person` edge if ownership must be queryable." }
11154
11436
  },
11155
11437
  // KeyActivityProperties: KeyActivity.
11156
11438
  key_activity: {
@@ -11159,7 +11441,7 @@ var UPG_PROPERTY_SCHEMA = {
11159
11441
  frequency_count: { type: "number", description: "Exact count of runs in the period. Pairs with `frequency_period`." },
11160
11442
  frequency_period: { type: "string", description: "Recurrence period (ISO-8601 `Duration`, e.g. `'P7D'`)" },
11161
11443
  frequency_rating: { type: "string", enum: ["constant", "regular", "occasional", "rare", "other"], description: "Qualitative tier. Use when an exact rate is unknown." },
11162
- operational_owner: { type: "string", description: "Operationally accountable team or individual" },
11444
+ operational_owner: { type: "string", description: "Operationally accountable team or individual. Promote to a `node_owned_by_team` edge if ownership must be queryable." },
11163
11445
  capacity_constraint: { type: "string", description: "Bottleneck or scaling constraint" },
11164
11446
  automation_level: { type: "string", enum: ["manual", "assisted", "automated"], description: "How much runs without human intervention" }
11165
11447
  },
@@ -11167,7 +11449,7 @@ var UPG_PROPERTY_SCHEMA = {
11167
11449
  key_resource: {
11168
11450
  resource_type: { type: "string", enum: ["physical", "intellectual", "human", "financial"], description: "Category" },
11169
11451
  criticality: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Criticality to the business model" },
11170
- owner: { type: "string", description: "Accountable person or team" },
11452
+ owner: { type: "string", description: "Accountable person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
11171
11453
  scarcity_risk: {
11172
11454
  type: "assessment",
11173
11455
  scale_id: "severity_5",
@@ -11356,7 +11638,7 @@ var UPG_PROPERTY_SCHEMA = {
11356
11638
  range_min: { type: "number", description: "Minimum expected or baseline value" },
11357
11639
  range_max: { type: "number", description: "Maximum expected or ceiling value" },
11358
11640
  cadence: { type: "string", enum: ["continuous", "hourly", "daily", "weekly", "monthly", "quarterly", "yearly", "on_demand", "other"], description: "Measurement cadence. Canonical `Cadence` since v0.4.0. `'realtime'` migrates to `'continuous'`; all other values 1:1." },
11359
- owner: { type: "string", description: "Person or team responsible for tracking this metric" },
11641
+ owner: { type: "string", description: "Person or team responsible for tracking this metric. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
11360
11642
  metric_health: { type: "string", enum: ["healthy", "at_risk", "unhealthy", "unknown"], description: "Universal health rollup. Orthogonal to lifecycle and `guardrail_status`. Applies to every metric regardless of `designation`. `healthy` = trending well against target / inside safe range. `at_risk` = drifting, approaching breach or target shortfall. `unhealthy` = missed target or breached; action needed. `unknown` = no current reading or not yet measured. For guardrails specifically, `guardrail_status` remains the breach-specific signal (`safe`/`warning`/`breached`)." },
11361
11643
  guardrail_threshold_min: { type: "number", description: "Lower bound for guardrail safety (below this = breach)" },
11362
11644
  guardrail_threshold_max: { type: "number", description: "Upper bound for guardrail safety (above this = breach)" },
@@ -11543,7 +11825,7 @@ var UPG_PROPERTY_SCHEMA = {
11543
11825
  // OutcomeProperties: A measurable change in user or business state the product drives.
11544
11826
  outcome: {
11545
11827
  timeline: { type: "string", description: 'Target timeframe (e.g. "Q2 2026", "12 months")' },
11546
- owner: { type: "string", description: "Accountable person or team" },
11828
+ owner: { type: "string", description: "Accountable person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
11547
11829
  success_criteria: { type: "string", description: 'What "achieved" looks like, concretely. Pairs with `measurement_method`. @example "30-day retention above 40% for new signups"' },
11548
11830
  measurement_method: { type: "string", enum: ["quantitative", "qualitative", "mixed"], description: "Assessment approach. `quantitative` = metrics drive the call. `qualitative` = observation / interviews. `mixed` = both, weighted case-by-case." },
11549
11831
  current_state: { type: "string", description: "Baseline or latest read" },
@@ -11602,7 +11884,7 @@ var UPG_PROPERTY_SCHEMA = {
11602
11884
  },
11603
11885
  required: ["value", "label"]
11604
11886
  },
11605
- owner: { type: "string", description: "Internal owner" },
11887
+ owner: { type: "string", description: "Internal owner. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
11606
11888
  start_date: { type: "string", description: "Date the partnership became effective (ISO 8601)" }
11607
11889
  },
11608
11890
  // PaywallProperties: Paywall.
@@ -11730,7 +12012,7 @@ var UPG_PROPERTY_SCHEMA = {
11730
12012
  product_area: {
11731
12013
  strategic_priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Strategic priority assigned to this area" },
11732
12014
  description: { type: "string", description: "Narrative description of what this area covers" },
11733
- owner: { type: "string", description: "Person or team that owns this area" }
12015
+ owner: { type: "string", description: "Person or team that owns this area. Promote to a `node_owned_by_team` edge if ownership must be queryable." }
11734
12016
  },
11735
12017
  // ProgramProperties: Program.
11736
12018
  program: {
@@ -11841,7 +12123,7 @@ var UPG_PROPERTY_SCHEMA = {
11841
12123
  release_date: { type: "string", description: "Scheduled or actual release date (ISO)" },
11842
12124
  version: { type: "string", description: 'Semver or named version (e.g. "v2.1.0", "Beta 3")' },
11843
12125
  start_date: { type: "string", description: "ISO date work begins" },
11844
- owner: { type: "string", description: "Responsible person or team" }
12126
+ owner: { type: "string", description: "Responsible person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." }
11845
12127
  },
11846
12128
  // ReleaseStrategyProperties: Release strategy.
11847
12129
  release_strategy: {
@@ -11902,7 +12184,7 @@ var UPG_PROPERTY_SCHEMA = {
11902
12184
  // ReviewGateProperties: Review gate.
11903
12185
  review_gate: {
11904
12186
  gate_type: { type: "string", enum: ["human_review", "automated_check", "approval"], description: "Kind of review required at this gate" },
11905
- required_approvers: { type: "string[]", description: "People or roles that must approve" },
12187
+ required_approvers: { type: "string[]", description: "People or roles that must approve. Promote to `node_owned_by_person` edges (one per name) if ownership must be queryable." },
11906
12188
  gate_status: { type: "string", enum: ["pending", "approved", "rejected", "bypassed"], description: "Current approval status of the gate" }
11907
12189
  },
11908
12190
  // RiskProperties: Risk.
@@ -11942,7 +12224,7 @@ var UPG_PROPERTY_SCHEMA = {
11942
12224
  roadmap: {
11943
12225
  roadmap_type: { type: "string", enum: ["now_next_later", "quarterly", "release_based", "theme_based"], description: "Structure" },
11944
12226
  timeframe: { type: "string", description: "Covered timeframe" },
11945
- owner: { type: "string", description: "Owning person or team" }
12227
+ owner: { type: "string", description: "Owning person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." }
11946
12228
  },
11947
12229
  // RoadmapItemProperties: Roadmap item.
11948
12230
  roadmap_item: {
@@ -12082,7 +12364,7 @@ var UPG_PROPERTY_SCHEMA = {
12082
12364
  service: {
12083
12365
  service_type: { type: "string", enum: ["web", "api", "worker", "db", "queue", "library", "mobile", "docs", "lambda", "cli"], description: "Functional classification. Expanded from Backstage's component type vocabulary. `cli` added in 0.9.12." },
12084
12366
  tech_stack: { type: "string[]", description: 'Technologies used (e.g. ["TypeScript", "Postgres", "Redis"])' },
12085
- owner: { type: "string", description: "Owning person or team. Backstage marks this required; strongly recommended." },
12367
+ owner: { type: "string", description: "Owning person or team. Backstage marks this required; strongly recommended. Promote to a `node_owned_by_team` edge if ownership must be queryable." },
12086
12368
  lifecycle: { type: "string", enum: ["experimental", "production", "deprecated"], description: 'Service maturity. Answers "how mature is it?". `experimental` = early-stage. `production` = battle-tested. `deprecated` = being phased out.' },
12087
12369
  tags: { type: "string[]", description: 'Free-form filter tags (e.g. ["payments", "critical-path", "team-alpha"]).' },
12088
12370
  links: { type: "object[]", description: "Named URLs for documentation, dashboards, runbooks." }
@@ -12103,7 +12385,7 @@ var UPG_PROPERTY_SCHEMA = {
12103
12385
  agreement_term: { type: "string", description: 'Effective term of the agreement (e.g. "12 months", "auto-renewing annual")' },
12104
12386
  effective_date: { type: "string", description: "ISO date effective" },
12105
12387
  expiry_date: { type: "string", description: "ISO date expires. Pairs with `agreement_term` for renewal logic." },
12106
- owner: { type: "string", description: "Party accountable on the service provider side" },
12388
+ owner: { type: "string", description: "Party accountable on the service provider side. Promote to a `node_owned_by_team` edge if ownership must be queryable." },
12107
12389
  consequence_of_breach: { type: "string", description: "What happens if the SLA is breached (credits, penalties, escalation path)" }
12108
12390
  },
12109
12391
  // ServiceLevelIndicatorProperties: Service Level Indicator.
@@ -12250,7 +12532,7 @@ var UPG_PROPERTY_SCHEMA = {
12250
12532
  },
12251
12533
  // StrategicPillarProperties: StrategicPillar entity. Durable multi-year direction the product commits to.
12252
12534
  strategic_pillar: {
12253
- owner: { type: "string", description: "Owning person or team" },
12535
+ owner: { type: "string", description: "Owning person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
12254
12536
  description: { type: "string", description: "Narrative of the pillar's intent" },
12255
12537
  scope: { type: "string", description: "What this pillar covers" },
12256
12538
  time_horizon: { type: "string", description: 'Planning horizon. Typically multi-year. @example "3 years", "2026-2028"' },
@@ -12258,7 +12540,7 @@ var UPG_PROPERTY_SCHEMA = {
12258
12540
  },
12259
12541
  // StrategicThemeProperties: StrategicTheme entity.
12260
12542
  strategic_theme: {
12261
- owner: { type: "string", description: "Owning person or team" },
12543
+ owner: { type: "string", description: "Owning person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
12262
12544
  time_horizon: { type: "string", description: 'Planning horizon. @example "Q1 2026", "FY26"' },
12263
12545
  description: { type: "string", description: "Short narrative of what the theme is about" },
12264
12546
  scope: { type: "string", description: "What the theme explicitly includes or excludes" }
@@ -12351,7 +12633,7 @@ var UPG_PROPERTY_SCHEMA = {
12351
12633
  },
12352
12634
  // TaskProperties: Task: a discrete unit of work, smaller than a story.
12353
12635
  task: {
12354
- assignee: { type: "string", description: "Assigned person" },
12636
+ assignee: { type: "string", description: "Assigned person. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
12355
12637
  effort: { type: "string", description: 'Effort estimate (e.g. "2h", "1d", "3 points"). Use a consistent unit within your team.' },
12356
12638
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Relative importance against other tasks" },
12357
12639
  due_date: { type: "string", description: "ISO date due. Typically bounded by the containing story's due date." },
@@ -12397,7 +12679,7 @@ var UPG_PROPERTY_SCHEMA = {
12397
12679
  },
12398
12680
  required: ["value", "label"]
12399
12681
  },
12400
- owner: { type: "string", description: "Owning person or team responsible for paydown." },
12682
+ owner: { type: "string", description: "Owning person or team responsible for paydown. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
12401
12683
  affected_area: { type: "string", description: 'Codebase location, service, or module. @example "apps/graph/src/canvas/", "UserService", "auth module"' },
12402
12684
  interest: { type: "string", description: 'Ongoing cost of leaving it unresolved (the "interest" in the financial metaphor). @example "~2h/sprint of workarounds", "blocks type-safe refactor of checkout"' },
12403
12685
  intentionality: { type: "string", enum: ["deliberate", "inadvertent"], description: "Origin of the debt. `deliberate` = conscious decision to ship something imperfect (prudent or reckless). `inadvertent` = discovered after the fact. Based on Fowler's Technical Debt Quadrant." }
@@ -12505,7 +12787,7 @@ var UPG_PROPERTY_SCHEMA = {
12505
12787
  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' },
12506
12788
  scope: { type: "string", description: 'What system, feature, or data flow is being analysed. @example "user authentication", "payment processing", "admin API"' },
12507
12789
  last_reviewed: { type: "string", description: 'ISO date last reviewed. Models become stale as systems evolve. @example "2026-03-01"' },
12508
- participants: { type: "string", description: 'Participants in the exercise. @example "Alice Chen (security lead), Bob Park (backend engineer), Carol Liu (architect)"' },
12790
+ 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.' },
12509
12791
  threat_count: { type: "number", description: "Threats identified. Key metric for scope and completeness. @example 12" }
12510
12792
  },
12511
12793
  // TouchpointProperties: Customer touchpoint.
@@ -28932,7 +29214,7 @@ function isCanonical(text) {
28932
29214
  }
28933
29215
 
28934
29216
  // src/index.ts
28935
- var UPG_VERSION = "0.12.3";
29217
+ var UPG_VERSION = "0.12.4";
28936
29218
  var UPG_FORMAT_VERSION = "0.4.0";
28937
29219
  var MARKDOWN_FORMAT_VERSION = "0.1";
28938
29220
  var UPG_TYPES = getTypes();