@unified-product-graph/core 0.11.5 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -494,7 +494,7 @@ var UPG_DOMAINS = [
494
494
  id: "foundations",
495
495
  label: "Foundations",
496
496
  description: "The shared specifications and foundational primitives a product organisation stewards or implements everywhere. Specifications are governed specs (query languages, protocols, data formats, encodings) like GROQ or Portable Text; primitives are the compositional units those specs define (a block, a reference, a query value). Both are registry-hostable canonicals that products implement, expose, or conform to. Distinct from a product feature: a specification has no single owner, no P&L, and no buyer; it is the rulebook many products point at.",
497
- types: ["specification", "primitive"]
497
+ types: ["specification", "primitive", "operating_lifecycle", "operating_stage"]
498
498
  }
499
499
  ];
500
500
  var UPG_ENTITY_TO_DOMAIN = Object.freeze(
@@ -517,6 +517,8 @@ var UPG_ENTITY_META = [
517
517
  // Foundations (0.9.12): shared specifications + the primitives they define.
518
518
  { name: "specification", type_id: "ent_352", maturity: "proposed", since: "0.9.12" },
519
519
  { name: "primitive", type_id: "ent_353", maturity: "proposed", since: "0.9.12" },
520
+ { name: "operating_lifecycle", type_id: "ent_355", maturity: "proposed", since: "0.11.6" },
521
+ { name: "operating_stage", type_id: "ent_356", maturity: "proposed", since: "0.11.6" },
520
522
  // ── Strategic ──
521
523
  { name: "product", type_id: "ent_001", maturity: "stable", since: "0.1.0" },
522
524
  { name: "outcome", type_id: "ent_002", maturity: "stable", since: "0.1.0" },
@@ -1017,6 +1019,9 @@ var UPG_EDGE_CATALOG = {
1017
1019
  persona_pursues_job: { forward_verb: "pursues", reverse_verb: "pursued_by", classification: "semantic", source_type: "persona", target_type: "job" },
1018
1020
  persona_experiences_need: { forward_verb: "experiences", reverse_verb: "experienced_by", classification: "semantic", source_type: "persona", target_type: "need" },
1019
1021
  persona_aspires_to_desired_outcome: { forward_verb: "aspires_to", reverse_verb: "aspirational_for", classification: "hierarchy", source_type: "persona", target_type: "desired_outcome" },
1022
+ // Delegation (0.11.6): a persona delegates work to another. The common case is human -> agent
1023
+ // (Content Ops Lead -> Content Agent), but it also expresses human -> human (editor -> reviewer).
1024
+ persona_delegates_to_persona: { forward_verb: "delegates_to", reverse_verb: "delegated_by", classification: "semantic", source_type: "persona", target_type: "persona" },
1020
1025
  persona_incurs_switching_cost: { forward_verb: "incurs", reverse_verb: "incurred_by", classification: "hierarchy", source_type: "persona", target_type: "switching_cost" },
1021
1026
  job_surfaces_need: { forward_verb: "surfaces", reverse_verb: "surfaces_from", classification: "causal", source_type: "job", target_type: "need" },
1022
1027
  job_motivates_desired_outcome: { forward_verb: "motivates", reverse_verb: "motivated_by", classification: "causal", source_type: "job", target_type: "desired_outcome" },
@@ -2179,6 +2184,32 @@ var UPG_EDGE_CATALOG = {
2179
2184
  // owned by feature_area / theme / product. Relationship is semantic.
2180
2185
  changelog_includes_feature: { forward_verb: "includes", reverse_verb: "included_in", classification: "semantic", source_type: "changelog", target_type: "feature" },
2181
2186
  ai_trace_spawns_ai_trace: { forward_verb: "spawns", reverse_verb: "spawned_by", classification: "hierarchy", source_type: "ai_trace", target_type: "ai_trace" },
2187
+ // ── P14 conformance edges (0.12.0) — promote orphan entity-reference scalars ──
2188
+ // Each replaces a string property that named a first-class entity. The matching
2189
+ // `UPGScalarToEdgeMigration['0.12.0']` rule losslessly mints/links + drops the
2190
+ // scalar. See the P14 string-reference sweep.
2191
+ business_model_guided_by_metric: { forward_verb: "guided_by", reverse_verb: "guides", classification: "cross-domain", source_type: "business_model", target_type: "metric" },
2192
+ vision_anchored_by_metric: { forward_verb: "anchored_by", reverse_verb: "anchors", classification: "cross-domain", source_type: "vision", target_type: "metric" },
2193
+ metric_fed_by_data_source: { forward_verb: "fed_by", reverse_verb: "feeds", classification: "cross-domain", source_type: "metric", target_type: "data_source" },
2194
+ hallucination_report_has_root_cause: { forward_verb: "has_root_cause", reverse_verb: "root_cause_of", classification: "causal", source_type: "hallucination_report", target_type: "root_cause" },
2195
+ model_comparison_compares_ai_model: { forward_verb: "compares", reverse_verb: "compared_in", classification: "semantic", source_type: "model_comparison", target_type: "ai_model" },
2196
+ launch_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "cross-domain", source_type: "launch", target_type: "metric" },
2197
+ wireframe_depicts_screen: { forward_verb: "depicts", reverse_verb: "depicted_by", classification: "semantic", source_type: "wireframe", target_type: "screen" },
2198
+ service_level_indicator_measures_metric: { forward_verb: "measures", reverse_verb: "measured_by", classification: "cross-domain", source_type: "service_level_indicator", target_type: "metric" },
2199
+ agent_definition_uses_ai_model: { forward_verb: "uses", reverse_verb: "used_by", classification: "semantic", source_type: "agent_definition", target_type: "ai_model" },
2200
+ privacy_policy_governs_compliance_requirement: { forward_verb: "governs", reverse_verb: "governed_by", classification: "semantic", source_type: "privacy_policy", target_type: "compliance_requirement" },
2201
+ a11y_annotation_targets_design_component: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "cross-domain", source_type: "a11y_annotation", target_type: "design_component" },
2202
+ metric_quality_assessment_considers_proxy_metric: { forward_verb: "considers_proxy", reverse_verb: "proxy_for", classification: "semantic", source_type: "metric_quality_assessment", target_type: "metric" },
2203
+ ai_experiment_based_on_ai_model: { forward_verb: "based_on", reverse_verb: "basis_for", classification: "semantic", source_type: "ai_experiment", target_type: "ai_model" },
2204
+ rebuttal_supported_by_evidence: { forward_verb: "supported_by", reverse_verb: "supports", classification: "cross-domain", source_type: "rebuttal", target_type: "evidence" },
2205
+ bug_observed_in_release: { forward_verb: "observed_in", reverse_verb: "exhibits", classification: "semantic", source_type: "bug", target_type: "release" },
2206
+ vulnerability_affects_library_dependency: { forward_verb: "affects", reverse_verb: "affected_by", classification: "cross-domain", source_type: "vulnerability", target_type: "library_dependency" },
2207
+ a11y_issue_found_in_screen: { forward_verb: "found_in", reverse_verb: "site_of", classification: "cross-domain", source_type: "a11y_issue", target_type: "screen" },
2208
+ team_okr_cascades_from_team_okr: { forward_verb: "cascades_from", reverse_verb: "cascades_to", classification: "semantic", source_type: "team_okr", target_type: "team_okr" },
2209
+ agent_session_invoked_agent_skill: { forward_verb: "invoked", reverse_verb: "invoked_by", classification: "semantic", source_type: "agent_session", target_type: "agent_skill" },
2210
+ agent_task_uses_agent_skill: { forward_verb: "uses", reverse_verb: "used_by", classification: "semantic", source_type: "agent_task", target_type: "agent_skill" },
2211
+ participant_belongs_to_behavioral_segment: { forward_verb: "belongs_to", reverse_verb: "includes", classification: "cross-domain", source_type: "participant", target_type: "behavioral_segment" },
2212
+ classification_axis_owned_by_product: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "classification_axis", target_type: "product" },
2182
2213
  // ── Part 9: Cross-Layer Influence Edges ────────────────────────────────────
2183
2214
  product_expressed_as_design_component: { forward_verb: "expressed_as", reverse_verb: "expresses", classification: "cross-domain", source_type: "product", target_type: "design_component" },
2184
2215
  product_manifests_in_design_component: { forward_verb: "manifests_in", reverse_verb: "manifested_by", classification: "cross-domain", source_type: "product", target_type: "design_component" },
@@ -2998,8 +3029,13 @@ var UPG_EDGE_CATALOG = {
2998
3029
  specification_competes_with_specification: { forward_verb: "competes_with", reverse_verb: "competes_with", classification: "semantic", source_type: "specification", target_type: "specification" },
2999
3030
  primitive_defined_by_specification: { forward_verb: "defined_by", reverse_verb: "defines", classification: "semantic", source_type: "primitive", target_type: "specification" },
3000
3031
  primitive_composes_primitive: { forward_verb: "composes", reverse_verb: "composed_by", classification: "hierarchy", source_type: "primitive", target_type: "primitive" },
3032
+ operating_lifecycle_contains_operating_stage: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "operating_lifecycle", target_type: "operating_stage" },
3001
3033
  // Stewardship: a registry specification is governed by a (registry-hostable) organization (0.9.13).
3002
- specification_governed_by_organization: { forward_verb: "governed_by", reverse_verb: "governs", classification: "semantic", source_type: "specification", target_type: "organization" }
3034
+ specification_governed_by_organization: { forward_verb: "governed_by", reverse_verb: "governs", classification: "semantic", source_type: "specification", target_type: "organization" },
3035
+ // Operating-lifecycle cross-edges (0.11.6): a product's journey phase realises a canonical
3036
+ // operating stage (the cross-surface join key); a stage is measured by a rollup metric (loop close).
3037
+ journey_phase_realises_operating_stage: { forward_verb: "realises", reverse_verb: "realised_by", classification: "cross-domain", source_type: "journey_phase", target_type: "operating_stage" },
3038
+ operating_stage_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "cross-domain", source_type: "operating_stage", target_type: "metric" }
3003
3039
  };
3004
3040
  var UPG_POLYMORPHIC_EDGE_KEYS = [
3005
3041
  // Universal semantic verbs
@@ -3155,6 +3191,9 @@ var UPG_VALID_CHILDREN = {
3155
3191
  // primitive_composes_primitive catalog edges.
3156
3192
  specification: ["specification"],
3157
3193
  primitive: ["primitive"],
3194
+ // An operating_lifecycle (e.g. the content-ops lifecycle) contains its ordered
3195
+ // operating_stage children. Backs the operating_lifecycle_contains_operating_stage edge.
3196
+ operating_lifecycle: ["operating_stage"],
3158
3197
  // ── Product (root) ─────────────────────────────────────────────────────────
3159
3198
  product: [
3160
3199
  // Strategy
@@ -6218,9 +6257,13 @@ function getLifecycleForType(entityType) {
6218
6257
  return UPG_LIFECYCLES.find((l) => l.entity_type === entityType);
6219
6258
  }
6220
6259
  var UPG_LIFECYCLE_FREE_TYPES = /* @__PURE__ */ new Set([
6221
- // ── Foundations (1 of 2): a primitive either exists or is deprecated; no
6222
- // phase ladder (like metric). `specification` carries a lifecycle. ──
6260
+ // ── Foundations (3 of 4): a primitive either exists or is deprecated; no
6261
+ // phase ladder (like metric). `operating_lifecycle`/`operating_stage` are
6262
+ // static ordered reference data (the loop is a `cyclic` flag, not a state
6263
+ // machine). `specification` carries a lifecycle. ──
6223
6264
  "primitive",
6265
+ "operating_lifecycle",
6266
+ "operating_stage",
6224
6267
  // ── User (5): personas and JTBD atoms are reference data ──────────────────
6225
6268
  "persona",
6226
6269
  "job",
@@ -7305,6 +7348,25 @@ function getDeprecatedTypes() {
7305
7348
  return deprecated;
7306
7349
  }
7307
7350
  var UPG_PROPERTY_MIGRATIONS = {
7351
+ // ── v0.12.0: P14 Bucket C — drop the one non-derived denormalized aggregate ──
7352
+ //
7353
+ // The count caches (feature_count, evidence_count, workflow step_count /
7354
+ // agent_count) are KEPT — 0.11.6 marked them `modifier:'derived'` (the
7355
+ // sanctioned "derived cache" reframe), so tooling knows to recompute rather
7356
+ // than removing them. `business_model.monetisation_basis` is NOT a count: it's
7357
+ // a categorical rollup of the model's revenue_stream.billing_model children, so
7358
+ // it drops here. `pattern` stays (a chosen archetype, not a rollup).
7359
+ // (customer_health_score.metrics — a metric→value map — is deferred: dropping
7360
+ // it is lossy until the per-metric values move onto the composed_of_metric
7361
+ // edges; tracked as a follow-up.)
7362
+ "0.12.0": [
7363
+ {
7364
+ kind: "drop_props",
7365
+ type: "business_model",
7366
+ drop_props: ["monetisation_basis"],
7367
+ reason: "P14 Bucket C: monetisation_basis is a categorical rollup of the model\u2019s revenue_stream.billing_model children, not a first-class attribute. Drop it; KEEP `pattern` (a chosen archetype)."
7368
+ }
7369
+ ],
7308
7370
  // ── v0.10.2: market_intelligence number -> assessment reshape ──────────────
7309
7371
  //
7310
7372
  // The v0.10.0 property-registry generator fix (#43) corrected several property
@@ -8134,6 +8196,245 @@ function getSplitMigrations(fromVersion, toVersion) {
8134
8196
  }
8135
8197
  return result;
8136
8198
  }
8199
+ var UPG_SCALAR_TO_EDGE_MIGRATIONS = {
8200
+ "0.12.0": [
8201
+ // ── Bucket A1 — orphan scalars (no edge existed): add edge + migrate + drop ──
8202
+ {
8203
+ from_type: "business_model",
8204
+ scalar_property: "north_star_metric",
8205
+ target_type: "metric",
8206
+ edge_type: "business_model_guided_by_metric",
8207
+ target_match: "title",
8208
+ target_defaults: { designation: "north_star" },
8209
+ drop_scalar: true,
8210
+ reason: 'P14: the optimised metric is a first-class entity you query across business models ("which models optimise for this metric"), not a label. Mint metric{designation:north_star} + link via business_model_guided_by_metric; drop the orphan string.'
8211
+ },
8212
+ // NOTE: revenue_stream.forecast is NOT promoted — its JSDoc ("Free-text
8213
+ // forecast or projection") is narrative prose, not a ref to a forecast
8214
+ // entity. The additive revenue_stream_projected_by_forecast edge exists for
8215
+ // an explicit stream→forecast link; the free-text field stays.
8216
+ {
8217
+ from_type: "metric",
8218
+ scalar_property: "data_source",
8219
+ target_type: "data_source",
8220
+ edge_type: "metric_fed_by_data_source",
8221
+ drop_scalar: true,
8222
+ reason: 'P14: the data source feeding a metric is queryable across metrics ("everything fed by this source"); promote the string to a metric_fed_by_data_source edge.'
8223
+ },
8224
+ {
8225
+ from_type: "hallucination_report",
8226
+ scalar_property: "root_cause",
8227
+ target_type: "root_cause",
8228
+ edge_type: "hallucination_report_has_root_cause",
8229
+ drop_scalar: true,
8230
+ reason: "P14: a root_cause is a first-class entity reused across reports; link it rather than restating the cause as a string."
8231
+ },
8232
+ // NOTE: prompt_version.template is NOT promoted — its JSDoc ("Template body
8233
+ // with variable placeholders") is the prompt CONTENT, not a ref to a
8234
+ // prompt_template entity. The additive prompt_version_child_of_prompt_template
8235
+ // edge exists for an explicit version→template link; the content field stays.
8236
+ {
8237
+ from_type: "model_comparison",
8238
+ scalar_property: "model_ids",
8239
+ target_type: "ai_model",
8240
+ edge_type: "model_comparison_compares_ai_model",
8241
+ multi: true,
8242
+ drop_scalar: true,
8243
+ reason: "P14: the models being compared are first-class ai_model entities; one compares edge per model replaces the id-string list."
8244
+ },
8245
+ {
8246
+ from_type: "launch",
8247
+ scalar_property: "success_metrics",
8248
+ target_type: "metric",
8249
+ edge_type: "launch_measured_by_metric",
8250
+ multi: true,
8251
+ drop_scalar: true,
8252
+ reason: "P14: success metrics are first-class metric entities measured across launches; one measured_by edge per metric replaces the string list."
8253
+ },
8254
+ // NOTE: user_story.as_a is NOT promoted — it is a load-bearing field of the
8255
+ // user_story → story_statement split (the "As a <persona>" templated promise),
8256
+ // and the value is often a role descriptor, not a persona node. Left in place.
8257
+ {
8258
+ from_type: "wireframe",
8259
+ scalar_property: "screen_name",
8260
+ target_type: "screen",
8261
+ edge_type: "wireframe_depicts_screen",
8262
+ drop_scalar: true,
8263
+ reason: "P14: the depicted screen is a first-class entity; link it via wireframe_depicts_screen rather than naming it in a string."
8264
+ },
8265
+ {
8266
+ from_type: "service_level_indicator",
8267
+ scalar_property: "metric_name",
8268
+ target_type: "metric",
8269
+ edge_type: "service_level_indicator_measures_metric",
8270
+ drop_scalar: true,
8271
+ reason: "P14: the SLI\u2019s metric is a first-class entity; link it via service_level_indicator_measures_metric rather than naming it in a string."
8272
+ },
8273
+ {
8274
+ from_type: "agent_definition",
8275
+ scalar_property: "model_ref",
8276
+ target_type: "ai_model",
8277
+ edge_type: "agent_definition_uses_ai_model",
8278
+ drop_scalar: true,
8279
+ reason: 'P14: the model an agent uses is a first-class ai_model entity ("every agent on this model"); promote the ref string to a uses edge.'
8280
+ },
8281
+ {
8282
+ from_type: "privacy_policy",
8283
+ scalar_property: "regulations",
8284
+ target_type: "compliance_requirement",
8285
+ edge_type: "privacy_policy_governs_compliance_requirement",
8286
+ multi: true,
8287
+ drop_scalar: true,
8288
+ reason: "P14: each regulation is a first-class compliance_requirement entity tracked across policies; one governs edge per requirement replaces the string list."
8289
+ },
8290
+ {
8291
+ from_type: "a11y_annotation",
8292
+ scalar_property: "target_component",
8293
+ target_type: "design_component",
8294
+ edge_type: "a11y_annotation_targets_design_component",
8295
+ drop_scalar: true,
8296
+ reason: "P14: the annotated component is a real design_component entity; link it so accessibility coverage rolls up by component."
8297
+ },
8298
+ {
8299
+ from_type: "metric_quality_assessment",
8300
+ scalar_property: "proxy_alternatives",
8301
+ target_type: "metric",
8302
+ edge_type: "metric_quality_assessment_considers_proxy_metric",
8303
+ multi: true,
8304
+ drop_scalar: true,
8305
+ reason: "P14: proxy alternatives are first-class metric entities; one considers_proxy edge per metric replaces the name list."
8306
+ },
8307
+ {
8308
+ from_type: "ai_experiment",
8309
+ scalar_property: "foundation_model",
8310
+ target_type: "ai_model",
8311
+ edge_type: "ai_experiment_based_on_ai_model",
8312
+ drop_scalar: true,
8313
+ reason: "P14: the foundation model is a first-class ai_model entity reused across experiments; promote the string to a based_on edge."
8314
+ },
8315
+ {
8316
+ from_type: "rebuttal",
8317
+ scalar_property: "evidence_refs",
8318
+ target_type: "evidence",
8319
+ edge_type: "rebuttal_supported_by_evidence",
8320
+ multi: true,
8321
+ drop_scalar: true,
8322
+ reason: "P14: each evidence ref is a first-class evidence entity; one supported_by edge per item replaces the ref-string list."
8323
+ },
8324
+ {
8325
+ from_type: "bug",
8326
+ scalar_property: "affected_version",
8327
+ target_type: "release",
8328
+ edge_type: "bug_observed_in_release",
8329
+ drop_scalar: true,
8330
+ reason: 'P14: the affected version is a first-class release entity ("every bug in this release"); promote the version string to an observed_in edge.'
8331
+ },
8332
+ {
8333
+ from_type: "vulnerability",
8334
+ scalar_property: "affected_package",
8335
+ target_type: "library_dependency",
8336
+ edge_type: "vulnerability_affects_library_dependency",
8337
+ drop_scalar: true,
8338
+ reason: "P14: the affected package is a first-class library_dependency entity; link it so vulnerabilities roll up by dependency."
8339
+ },
8340
+ {
8341
+ from_type: "a11y_issue",
8342
+ scalar_property: "discovered_in",
8343
+ target_type: "screen",
8344
+ edge_type: "a11y_issue_found_in_screen",
8345
+ drop_scalar: true,
8346
+ reason: "P14: the screen an issue was found in is a real screen entity; link it so issues roll up by screen rather than naming it in a string."
8347
+ },
8348
+ {
8349
+ from_type: "team_okr",
8350
+ scalar_property: "cascade_from",
8351
+ target_type: "team_okr",
8352
+ edge_type: "team_okr_cascades_from_team_okr",
8353
+ drop_scalar: true,
8354
+ reason: "P14: a cascaded OKR points at its parent OKR (a real entity); the cascade is a self-referential edge, not a name string."
8355
+ },
8356
+ {
8357
+ from_type: "agent_session",
8358
+ scalar_property: "tools_invoked",
8359
+ target_type: "agent_skill",
8360
+ edge_type: "agent_session_invoked_agent_skill",
8361
+ multi: true,
8362
+ drop_scalar: true,
8363
+ reason: "P14: invoked tools are first-class agent_skill entities tracked across sessions; one invoked edge per skill replaces the string list."
8364
+ },
8365
+ {
8366
+ from_type: "agent_task",
8367
+ scalar_property: "tools",
8368
+ target_type: "agent_skill",
8369
+ edge_type: "agent_task_uses_agent_skill",
8370
+ multi: true,
8371
+ drop_scalar: true,
8372
+ reason: "P14: the tools a task uses are first-class agent_skill entities; one uses edge per skill replaces the string list."
8373
+ },
8374
+ {
8375
+ from_type: "participant",
8376
+ scalar_property: "segment",
8377
+ target_type: "behavioral_segment",
8378
+ edge_type: "participant_belongs_to_behavioral_segment",
8379
+ drop_scalar: true,
8380
+ reason: "P14: a participant\u2019s segment is a first-class behavioral_segment entity queried across studies; promote the string to a belongs_to edge."
8381
+ },
8382
+ {
8383
+ from_type: "classification_axis",
8384
+ scalar_property: "owner_product",
8385
+ target_type: "product",
8386
+ edge_type: "classification_axis_owned_by_product",
8387
+ target_match: "id",
8388
+ drop_scalar: true,
8389
+ reason: "P14: the product that owns an axis is a first-class entity; link it via classification_axis_owned_by_product. The scalar holds a product id, so match by id (no mint)."
8390
+ },
8391
+ // ── Bucket A2 — shadow scalars (the canonical edge ALREADY exists): backfill + drop ──
8392
+ {
8393
+ from_type: "growth_campaign",
8394
+ scalar_property: "channels_targeted",
8395
+ target_type: "acquisition_channel",
8396
+ edge_type: "acquisition_channel_runs_growth_campaign",
8397
+ reverse: true,
8398
+ multi: true,
8399
+ drop_scalar: true,
8400
+ reason: "P14 shadow: the acquisition_channel_runs_growth_campaign edge already exists (channel\u2192campaign). Backfill any string-only channels as edges, then drop the drift-prone list."
8401
+ },
8402
+ {
8403
+ from_type: "journey_step",
8404
+ scalar_property: "touchpoint",
8405
+ target_type: "touchpoint",
8406
+ edge_type: "touchpoint_occurs_in_journey_step",
8407
+ reverse: true,
8408
+ drop_scalar: true,
8409
+ reason: "P14 shadow: the touchpoint_occurs_in_journey_step edge already exists (touchpoint\u2192journey_step) and the field was @deprecated 0.9.9. Backfill + finish the drop."
8410
+ },
8411
+ {
8412
+ from_type: "decision",
8413
+ scalar_property: "superseded_by",
8414
+ target_type: "decision",
8415
+ edge_type: "decision_superseded_by_decision",
8416
+ drop_scalar: true,
8417
+ reason: "P14 shadow: the decision_superseded_by_decision edge already exists. Backfill the superseding decision as an edge, then drop the reference string."
8418
+ },
8419
+ {
8420
+ from_type: "subscription",
8421
+ scalar_property: "plan_name",
8422
+ target_type: "pricing_tier",
8423
+ edge_type: "subscription_subscribes_to_pricing_tier",
8424
+ drop_scalar: true,
8425
+ 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."
8426
+ }
8427
+ ]
8428
+ };
8429
+ function getScalarToEdgeMigrations(fromVersion, toVersion) {
8430
+ const result = [];
8431
+ for (const [version, migrations] of Object.entries(UPG_SCALAR_TO_EDGE_MIGRATIONS)) {
8432
+ if (versionInRange(version, fromVersion, toVersion)) {
8433
+ result.push(...migrations);
8434
+ }
8435
+ }
8436
+ return result;
8437
+ }
8137
8438
  var UPG_EDGE_MIGRATIONS = {
8138
8439
  "0.9.9": [
8139
8440
  // (since v0.9.9, UPG-664/UPG-678) Validation experiment-model + test_plan
@@ -9122,7 +9423,6 @@ var UPG_PROPERTY_SCHEMA = {
9122
9423
  // A11yAnnotationProperties: Accessibility annotation.
9123
9424
  a11y_annotation: {
9124
9425
  category: { type: "string", enum: ["focus_order", "alt_text", "heading_level", "aria_label", "colour_contrast", "keyboard_nav", "screen_reader", "motion_preference", "other"], description: "Category of accessibility annotation. Expanded from the original 5-value enum to cover the full range of a11y annotation types." },
9125
- target_component: { type: "string", description: "Component or element this annotation applies to" },
9126
9426
  requirement: { type: "string", description: "Specific accessibility requirement described" },
9127
9427
  wcag_criterion: { type: "string", description: "WCAG success criterion this annotation relates to" },
9128
9428
  annotation_priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Priority for implementing this annotation" },
@@ -9171,8 +9471,7 @@ var UPG_PROPERTY_SCHEMA = {
9171
9471
  html_snippet: { type: "string", description: "HTML snippet containing the violation" },
9172
9472
  tags: { type: "string[]", description: 'Tags from the audit tool (e.g. "wcag2aa", "cat.color")' },
9173
9473
  remediation: { type: "string", description: "Recommended fix for the issue" },
9174
- impact_description: { type: "string", description: "Description of the user impact" },
9175
- discovered_in: { type: "string", description: "Page or component where the issue was found" }
9474
+ impact_description: { type: "string", description: "Description of the user impact" }
9176
9475
  },
9177
9476
  // A11yStandardProperties: Accessibility standard.
9178
9477
  a11y_standard: {
@@ -9238,7 +9537,6 @@ var UPG_PROPERTY_SCHEMA = {
9238
9537
  agent_scope: { type: "string", description: "Boundaries of what this agent can act on" },
9239
9538
  goal: { type: "string", description: "Primary objective the agent is trying to achieve" },
9240
9539
  backstory: { type: "string", description: "Context or persona narrative for the agent" },
9241
- model_ref: { type: "string", description: "Reference to the AI model powering this agent" },
9242
9540
  allow_delegation: { type: "boolean", description: "Whether the agent can delegate tasks to other agents" },
9243
9541
  memory_enabled: { type: "boolean", description: "Whether the agent retains memory across sessions" },
9244
9542
  max_iterations: { type: "number", description: "Maximum number of reasoning iterations allowed" },
@@ -9262,7 +9560,6 @@ var UPG_PROPERTY_SCHEMA = {
9262
9560
  turns: { type: "number", description: "Number of conversational turns in the session" },
9263
9561
  tokens_used: { type: "number", description: "Total tokens consumed during the session" },
9264
9562
  cost: { type: "number", description: "Total monetary cost of the session" },
9265
- tools_invoked: { type: "string[]", description: "List of tools invoked during the session" },
9266
9563
  error_count: { type: "number", description: "Number of errors encountered during the session" },
9267
9564
  session_status: { type: "string", enum: ["active", "completed", "errored", "timed_out"], description: "Current status of the session" },
9268
9565
  output_summary: { type: "string", description: "Brief summary of the session's output" }
@@ -9278,7 +9575,6 @@ var UPG_PROPERTY_SCHEMA = {
9278
9575
  description: { type: "string", description: "What the agent should accomplish" },
9279
9576
  expected_output: { type: "string", description: "Description of the expected output format or content" },
9280
9577
  context: { type: "string", description: "Additional context provided to the agent for this task" },
9281
- tools: { type: "string[]", description: "Tools the agent may use for this task" },
9282
9578
  output_file: { type: "string", description: "File path where the agent should write output" },
9283
9579
  blocking: { type: "boolean", description: "Whether this task blocks downstream tasks" },
9284
9580
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Relative priority of this task" }
@@ -9320,7 +9616,6 @@ var UPG_PROPERTY_SCHEMA = {
9320
9616
  summary_metrics: { type: "string", description: "Key-metric summary" },
9321
9617
  started_at: { type: "string", description: "ISO timestamp started" },
9322
9618
  completed_at: { type: "string", description: "ISO timestamp completed" },
9323
- foundation_model: { type: "string", description: "Foundation starting model" },
9324
9619
  training_steps: { type: "number", description: "Training steps or epochs completed" },
9325
9620
  artifact_uri: { type: "string", description: "Produced artifact URI" },
9326
9621
  notes: { type: "string", description: "Free-text notes" },
@@ -9551,7 +9846,6 @@ var UPG_PROPERTY_SCHEMA = {
9551
9846
  environment: { type: "string", description: 'Observed environment (e.g. "prod", "staging", "iOS 17.4")' },
9552
9847
  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)." },
9553
9848
  assignee: { type: "string", description: "Assigned person" },
9554
- affected_version: { type: "string", description: "Product version where first observed. Helps triage regressions." },
9555
9849
  due_date: { type: "string", description: "ISO date due. Often tied to a release gate or SLA." },
9556
9850
  labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." }
9557
9851
  },
@@ -9567,9 +9861,9 @@ var UPG_PROPERTY_SCHEMA = {
9567
9861
  business_model: {
9568
9862
  framework_id: { type: "string", description: "Framework ID (references `UPGFramework.id`)" },
9569
9863
  stage: { type: "string", enum: ["draft", "validated", "active"], description: "Maturity" },
9570
- 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." },
9571
- monetisation_basis: { type: "string", enum: ["usage", "seat", "outcome", "transaction", "flat"], description: "Primary monetisation unit" },
9572
- north_star_metric: { type: "string", description: "The single metric the business optimises for" }
9864
+ 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." }
9865
+ // monetisation_basis removed in 0.12.0 (P14 Bucket C) — categorical rollup of revenue_stream.billing_model.
9866
+ // north_star_metric removed in 0.12.0 (P14) → `business_model_guided_by_metric` edge.
9573
9867
  },
9574
9868
  // CapabilityProperties: Capability entity.
9575
9869
  capability: {
@@ -9637,8 +9931,7 @@ var UPG_PROPERTY_SCHEMA = {
9637
9931
  // ClassificationAxisProperties: ClassificationAxis: a dimension along which subjects are classified.
9638
9932
  classification_axis: {
9639
9933
  axis_kind: { type: "string", enum: ["categorical", "ordinal", "continuous"], description: "Structural kind of values on this axis. `categorical` = discrete, unordered (most common; CMS architectures). `ordinal` = discrete, ordered (maturity tiers, T-shirt sizes). `continuous` = numeric range (latency budget, price points)." },
9640
- cardinality: { type: "string", enum: ["single", "multi"], description: 'How many values a subject may hold on this axis at once (UPG 0.11.3). `single` (default) = a subject sits at exactly one value; a re-classification to a new value SUPERSEDES the prior one (the classify writer retires the old same-axis edge and records the move in the reclassification history). `multi` = a subject may legitimately hold several values at once (e.g. an axis like "supported frameworks"); re-classifying ADDS a value and does not supersede. A separate axis from `axis_kind`: an axis can be `categorical` (unordered) yet `single`-select, or `categorical` yet `multi`-select.' },
9641
- owner_product: { type: "string", description: "Product id when product-specific. Axes are usually product-agnostic; leave empty for shared taxonomies." }
9934
+ cardinality: { type: "string", enum: ["single", "multi"], description: 'How many values a subject may hold on this axis at once (UPG 0.11.3). `single` (default) = a subject sits at exactly one value; a re-classification to a new value SUPERSEDES the prior one (the classify writer retires the old same-axis edge and records the move in the reclassification history). `multi` = a subject may legitimately hold several values at once (e.g. an axis like "supported frameworks"); re-classifying ADDS a value and does not supersede. A separate axis from `axis_kind`: an axis can be `categorical` (unordered) yet `single`-select, or `categorical` yet `multi`-select.' }
9642
9935
  },
9643
9936
  // ClassificationValueProperties: ClassificationValue: a value on a classification axis.
9644
9937
  classification_value: {
@@ -9649,7 +9942,7 @@ var UPG_PROPERTY_SCHEMA = {
9649
9942
  },
9650
9943
  // CodeRepositoryProperties: Code repository.
9651
9944
  code_repository: {
9652
- repo_url: { type: "string", description: "URL" },
9945
+ repo_url: { type: "string", description: "URL", modifier: "volatile" },
9653
9946
  default_branch: { type: "string", description: "Default branch" },
9654
9947
  language: { type: "string", description: "Primary programming language" },
9655
9948
  ci_status: { type: "string", enum: ["passing", "failing", "unknown"], description: "Current CI status" },
@@ -9910,7 +10203,7 @@ var UPG_PROPERTY_SCHEMA = {
9910
10203
  data_classification: {
9911
10204
  level: { type: "string", enum: ["public", "internal", "confidential", "restricted"], description: "Sensitivity level" },
9912
10205
  handling_requirements: { type: "string", description: "Handling rules" },
9913
- examples: { type: "string", description: "Example data covered" },
10206
+ examples: { type: "string[]", description: "Example data covered" },
9914
10207
  retention_period: { type: "string", description: "Retention period" },
9915
10208
  encryption_required: { type: "boolean", description: "Whether encryption is mandatory" }
9916
10209
  },
@@ -10007,8 +10300,7 @@ var UPG_PROPERTY_SCHEMA = {
10007
10300
  decision_outcome: { type: "string", description: "Outcome text. What was decided. Separate from `rationale` (which explains why)." },
10008
10301
  consequences: { type: "string", description: `Known positive and negative consequences. Mirrors MADR's "Consequences" section.` },
10009
10302
  decision_makers: { type: "string[]", description: `People who made the decision. Mirrors MADR's "Deciders" field.` },
10010
- 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"]` },
10011
- superseded_by: { type: "string", description: "Reference to the superseding decision, if any." }
10303
+ 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"]` }
10012
10304
  },
10013
10305
  // DeliverableProperties: Deliverable.
10014
10306
  deliverable: {
@@ -10404,7 +10696,7 @@ var UPG_PROPERTY_SCHEMA = {
10404
10696
  feature_area: {
10405
10697
  scope_summary: { type: "string", description: "One-line scope description. Disambiguates from sibling areas at a glance." },
10406
10698
  owning_team: { type: "string", description: "Team identifier or slug. Free-form display. Canonical relationship is the `team_owns_feature_area` edge." },
10407
- feature_count: { type: "number", description: "Approximate feature count under this area. Snapshot; `feature_area_contains_feature` edges are the source of truth." },
10699
+ feature_count: { type: "number", description: "Approximate feature count under this area. Snapshot; `feature_area_contains_feature` edges are the source of truth.", modifier: "derived" },
10408
10700
  owner: { type: "string", description: "Area owner (handle or email)" },
10409
10701
  priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Importance to the product overall" },
10410
10702
  maturity: { type: "string", enum: ["nascent", "growing", "mature", "legacy"], description: "Maturity. `nascent` = newly-formed grouping. `mature` = established surface. `legacy` = being phased out for a successor." },
@@ -10521,7 +10813,7 @@ var UPG_PROPERTY_SCHEMA = {
10521
10813
  // FunnelProperties: Funnel entity.
10522
10814
  funnel: {
10523
10815
  funnel_type: { type: "string", enum: ["acquisition", "activation", "retention", "revenue", "referral", "custom"], description: "Which stage of the customer lifecycle this funnel measures" },
10524
- step_count: { type: "number", description: "Number of steps in the funnel" },
10816
+ step_count: { type: "number", description: "Number of steps in the funnel", modifier: "derived" },
10525
10817
  overall_conversion_rate: { type: "number", description: "End-to-end conversion rate through the funnel (0-1)" }
10526
10818
  },
10527
10819
  // FunnelStepProperties: FunnelStep entity.
@@ -10542,7 +10834,6 @@ var UPG_PROPERTY_SCHEMA = {
10542
10834
  end_date: { type: "string", description: "ISO end date" },
10543
10835
  budget_amount: { type: "number", description: "Total allocated budget. Use with `budget_currency`." },
10544
10836
  budget_currency: { type: "string", description: 'ISO 4217 currency code (e.g. "USD", "EUR", "GBP")' },
10545
- channels_targeted: { type: "string[]", description: 'Channels the campaign runs across. Free-form so partner channels and ad networks both fit (e.g. "google_ads", "linkedin", "podcast_sponsorship").' },
10546
10837
  primary_kpi: { type: "string", description: 'Primary KPI optimised for (e.g. "qualified_signups", "MQL_volume", "activated_teams")' },
10547
10838
  kpi_target: { type: "number", description: "Numeric target for `primary_kpi` over the campaign window" },
10548
10839
  utm_parameters: { type: "string", description: "UTM tracking parameters for this campaign" },
@@ -10576,7 +10867,6 @@ var UPG_PROPERTY_SCHEMA = {
10576
10867
  required: ["value", "label"]
10577
10868
  },
10578
10869
  user_facing: { type: "boolean", description: "Visible to end users" },
10579
- root_cause: { type: "string", description: "Identified cause" },
10580
10870
  remediation: { type: "string", description: "Remediation steps" }
10581
10871
  },
10582
10872
  // HelpVideoProperties: Help video.
@@ -10674,7 +10964,7 @@ var UPG_PROPERTY_SCHEMA = {
10674
10964
  },
10675
10965
  required: ["value", "label"]
10676
10966
  },
10677
- evidence_count: { type: "number", description: "Supporting observations, quotes, or evidence items. Higher counts increase confidence." },
10967
+ evidence_count: { type: "number", description: "Supporting observations, quotes, or evidence items. Higher counts increase confidence.", modifier: "derived" },
10678
10968
  novelty: { type: "string", enum: ["known", "surprising", "contradictory"], description: "Novelty against existing knowledge. `known` = confirms what we already believed. `surprising` = challenges or extends our understanding. `contradictory` = directly conflicts with a prior assumption." },
10679
10969
  actionability: { type: "string", enum: ["immediate", "needs_validation", "informational"], description: "Current actionability. `immediate` = clear action, no further research needed. `needs_validation` = promising but requires more evidence. `informational` = important context, no direct action." },
10680
10970
  source_method: { type: "string", description: 'Producing research method. @example "usability_study", "interview_series", "survey"' },
@@ -10830,7 +11120,6 @@ var UPG_PROPERTY_SCHEMA = {
10830
11120
  // JourneyStepProperties: Single step within a user journey. A user-moment on the journey's single
10831
11121
  journey_step: {
10832
11122
  step_order: { type: "number", description: "Display order within the journey's step timeline (0-indexed). The scalar ordering convention shared with `journey_phase.phase_order` and `journey_action.action_order` (UPG-663). For branching journeys, the explicit `journey_step_precedes_journey_step` edge captures the chain." },
10833
- touchpoint: { type: "string", description: "@deprecated since v0.9.9 (UPG-675). Touchpoints are modelled in two places, neither of which is this string: the `touchpoint` *entity* is the cross-channel customer-success layer (`touchpoint_occurs_in_journey_step`), and `journey_action` is the in-product blueprint layer (the finest band of a `journey_step`). Use one of those rather than a free-text string here. Removed in a future major." },
10834
11123
  channel: { type: "string", description: 'Channel (e.g. "web", "email", "in-store")' },
10835
11124
  emotion_score: {
10836
11125
  type: "assessment",
@@ -10903,8 +11192,7 @@ var UPG_PROPERTY_SCHEMA = {
10903
11192
  // LaunchProperties: Launch entity.
10904
11193
  launch: {
10905
11194
  launch_type: { type: "string", enum: ["soft", "beta", "public", "feature"], description: "Scale and audience of the launch" },
10906
- target_date: { type: "string", description: "Planned launch date (ISO format)" },
10907
- success_metrics: { type: "string[]", description: "Metrics that define launch success" }
11195
+ target_date: { type: "string", description: "Planned launch date (ISO format)" }
10908
11196
  },
10909
11197
  // LeadProperties: Lead.
10910
11198
  lead: {
@@ -11064,7 +11352,6 @@ var UPG_PROPERTY_SCHEMA = {
11064
11352
  range_min: { type: "number", description: "Minimum expected or baseline value" },
11065
11353
  range_max: { type: "number", description: "Maximum expected or ceiling value" },
11066
11354
  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." },
11067
- data_source: { type: "string", description: 'Data source or tool that feeds this metric (e.g. "PostHog", "Stripe")' },
11068
11355
  owner: { type: "string", description: "Person or team responsible for tracking this metric" },
11069
11356
  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`)." },
11070
11357
  guardrail_threshold_min: { type: "number", description: "Lower bound for guardrail safety (below this = breach)" },
@@ -11082,8 +11369,7 @@ var UPG_PROPERTY_SCHEMA = {
11082
11369
  quality_related: { type: "boolean", description: "Quality signal: metric relates to other key metrics in the system" },
11083
11370
  quality_score: { type: "number", description: "Computed quality score across all quality signals (0\u20135)" },
11084
11371
  proxy_reason: { type: "string", enum: ["qualitative", "no_direct_measure", "not_yet_instrumented", "too_expensive"], description: "Why this metric is used as a proxy instead of measuring directly" },
11085
- proxy_confidence: { type: "string", enum: ["strong", "moderate", "weak"], description: "How strongly this metric predicts the direct measure" },
11086
- proxy_alternatives: { type: "string[]", description: "Other metrics considered as proxy candidates" }
11372
+ proxy_confidence: { type: "string", enum: ["strong", "moderate", "weak"], description: "How strongly this metric predicts the direct measure" }
11087
11373
  },
11088
11374
  // MilestoneProperties: Milestone.
11089
11375
  milestone: {
@@ -11099,7 +11385,6 @@ var UPG_PROPERTY_SCHEMA = {
11099
11385
  },
11100
11386
  // ModelComparisonProperties: Model comparison.
11101
11387
  model_comparison: {
11102
- model_ids: { type: "string[]", description: "Compared model identifiers" },
11103
11388
  comparison_criteria: { type: "string[]", description: 'Comparison dimensions (e.g. "accuracy", "cost", "latency")' },
11104
11389
  comparison_date: { type: "string", description: "ISO conduct date" }
11105
11390
  },
@@ -11276,7 +11561,6 @@ var UPG_PROPERTY_SCHEMA = {
11276
11561
  // ParticipantProperties: Research participant.
11277
11562
  participant: {
11278
11563
  alias: { type: "string", description: 'Anonymous alias for privacy (e.g. "P01")' },
11279
- segment: { type: "string", description: "User segment this participant belongs to" },
11280
11564
  recruit_source: { type: "string", description: "How the participant was recruited" },
11281
11565
  consent_status: { type: "string", enum: ["pending", "given", "withdrawn"], description: "Current consent status for data usage" }
11282
11566
  },
@@ -11348,7 +11632,8 @@ var UPG_PROPERTY_SCHEMA = {
11348
11632
  motivation: { type: "string", description: 'Primary motivation or driving need @example "Making confident, evidence-based decisions"' },
11349
11633
  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`." },
11350
11634
  domain_expertise: { type: "string", description: 'Industry or domain knowledge this persona brings @example "10+ years SaaS experience", "New to healthcare IT"' },
11351
- 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"' }
11635
+ 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"' },
11636
+ 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." }
11352
11637
  },
11353
11638
  // PipelineSalesProperties: Sales pipeline.
11354
11639
  pipeline_sales: {
@@ -11411,13 +11696,27 @@ var UPG_PROPERTY_SCHEMA = {
11411
11696
  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." },
11412
11697
  since: { type: "string", description: "Year or version the primitive was introduced." }
11413
11698
  },
11699
+ // OperatingLifecycleProperties: a canonical ordered (often cyclic) operating process products' journey phases map onto.
11700
+ operating_lifecycle: {
11701
+ label: { type: "string", description: "Human-readable name of the operating process." },
11702
+ cyclic: { type: "boolean", description: "True if the process loops (e.g. Analyze \u2192 Extend \u2192 Plan). Rendered linearly by stage_order with the wrap on the final stage." },
11703
+ source: { type: "string", description: 'Origin of the canonical model (e.g. "Sanity official content-ops lifecycle").' }
11704
+ },
11705
+ // OperatingStageProperties: one ordered stage of an operating_lifecycle.
11706
+ operating_stage: {
11707
+ stage_order: { type: "number", description: "Ordered position within the lifecycle, 0-indexed." },
11708
+ label: { type: "string", description: "Human-readable stage name." },
11709
+ goal: { type: "string", description: "What this stage accomplishes." },
11710
+ owner_role: { type: "string", description: "Role that owns the stage (free-text role label)." },
11711
+ os_analogy: { type: "string", description: 'The Content-OS analogy from the source volume (e.g. "Drivers + daemons / cron").' },
11712
+ next_stage: { type: "string", description: "Label of the next stage; on the final stage of a cyclic lifecycle this carries the wrap." }
11713
+ },
11414
11714
  // PrivacyPolicyProperties: Privacy policy.
11415
11715
  privacy_policy: {
11416
11716
  version: { type: "string", description: "Version identifier of the policy" },
11417
11717
  last_updated: { type: "string", description: "Date the policy was last updated (ISO format)" },
11418
11718
  effective_date: { type: "string", description: "Date the policy takes effect (ISO format)" },
11419
- url: { type: "string", description: "URL where the policy is published" },
11420
- regulations: { type: "string[]", description: 'Regulations this policy addresses (e.g. "GDPR", "CCPA")' }
11719
+ url: { type: "string", description: "URL where the policy is published" }
11421
11720
  },
11422
11721
  // ProductProperties: The product being created. Root of the graph.
11423
11722
  product: {
@@ -11809,9 +12108,8 @@ var UPG_PROPERTY_SCHEMA = {
11809
12108
  },
11810
12109
  // ServiceLevelIndicatorProperties: Service Level Indicator.
11811
12110
  service_level_indicator: {
11812
- metric_name: { type: "string", description: 'Indicator metric name. @example "Request latency p99", "Error rate", "Availability"' },
11813
12111
  threshold: { type: "number", description: 'Threshold that defines a "good" event. @example 200 (ms latency), 0.01 (1% error rate), 99.9 (% availability)' },
11814
- current_value: { type: "number", description: "Current observed value. Compared against `threshold` for SLO compliance. @example 150 (ms), 0.003 (0.3% error rate)" },
12112
+ current_value: { type: "number", description: "Current observed value. Compared against `threshold` for SLO compliance. @example 150 (ms), 0.003 (0.3% error rate)", modifier: "snapshot" },
11815
12113
  unit: { type: "string", description: 'Unit of measurement. Required to interpret `threshold` and `current_value`. @example "ms", "%", "req/s", "errors/min"' },
11816
12114
  aggregation: { type: "string", enum: ["avg", "sum", "max", "min", "p50", "p95", "p99", "count"], description: 'Aggregation over the evaluation window. p99 and avg tell different stories. @example "p99" for tail latency, "avg" for mean throughput, "count" for total events' },
11817
12115
  measurement_query: { type: "string", description: "Query expression that produces `current_value`. Free-form to fit PromQL, Datadog query strings, SQL, or vendor-specific DSLs. @example 'sum(rate(http_requests_total{status=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m]))'" },
@@ -11967,7 +12265,6 @@ var UPG_PROPERTY_SCHEMA = {
11967
12265
  },
11968
12266
  // SubscriptionProperties: Subscription.
11969
12267
  subscription: {
11970
- plan_name: { type: "string", description: "Name of the subscribed plan" },
11971
12268
  monthly_recurring_revenue: { type: "number", description: "Monthly recurring revenue from this subscription" },
11972
12269
  start_date: { type: "string", description: "Subscription start date (ISO format)" },
11973
12270
  renewal_date: { type: "string", description: "Next renewal date (ISO format)" },
@@ -12060,8 +12357,7 @@ var UPG_PROPERTY_SCHEMA = {
12060
12357
  team_okr: {
12061
12358
  period: { type: "string", description: 'Time period for the OKR (e.g. "Q2 2026")' },
12062
12359
  progress: { type: "number", description: "Overall progress toward the objective (0-100%)" },
12063
- objective_statement: { type: "string", description: "The team-level objective statement (key results live in child entities)" },
12064
- cascade_from: { type: "string", description: "Higher-level objective this OKR cascades from (company or department OKR)" }
12360
+ objective_statement: { type: "string", description: "The team-level objective statement (key results live in child entities)" }
12065
12361
  },
12066
12362
  // TechnicalDebtItemProperties: Technical debt item.
12067
12363
  technical_debt_item: {
@@ -12314,7 +12610,6 @@ var UPG_PROPERTY_SCHEMA = {
12314
12610
  },
12315
12611
  cvss_version: { type: "string", enum: ["v3.1", "v4.0"], description: 'CVSS scoring version. v3.1 and v4.0 differ significantly for the same vulnerability. @example "v4.0" for vulnerabilities scored after the v4.0 release in 2023' },
12316
12612
  affected_component: { type: "string", description: 'Affected component, library, or system. @example "lodash", "openssl", "login service"' },
12317
- affected_package: { type: "string", description: 'Affected package with version. More precise than `affected_component`. @example "lodash@4.17.20", "openssl@1.1.1q"' },
12318
12613
  exploit_maturity: { type: "string", enum: ["no_known_exploit", "proof_of_concept", "functional_exploit", "active_exploitation"], description: 'Exploit maturity. Primary prioritisation factor after severity. `no_known_exploit` = theoretical. `proof_of_concept` = exploit code exists, not weaponised. `functional_exploit` = working exploit available. `active_exploitation` = active in the wild. @example "active_exploitation" demands immediate response regardless of severity score' },
12319
12614
  fix_available: { type: "boolean", description: "Patch availability. Common triage question after severity. @example false for a zero-day with no available patch" },
12320
12615
  disclosed_at: { type: "string", description: 'ISO date publicly disclosed. Time since disclosure matters for SLA. @example "2024-03-15"' },
@@ -12339,7 +12634,6 @@ var UPG_PROPERTY_SCHEMA = {
12339
12634
  // WireframeProperties: Wireframe.
12340
12635
  wireframe: {
12341
12636
  fidelity: { type: "string", enum: ["low", "medium", "high"], description: "Detail level" },
12342
- screen_name: { type: "string", description: "Represented screen name" },
12343
12637
  version: { type: "string", description: 'Version or iteration (e.g. "v2", "2026-04-B")' },
12344
12638
  tool: { type: "string", description: 'Authoring tool. @example "Figma", "Balsamiq", "pen and paper"' },
12345
12639
  review_status: { type: "string", enum: ["draft", "in_review", "approved", "rejected"], description: "Review gate status" },
@@ -12357,7 +12651,7 @@ var UPG_PROPERTY_SCHEMA = {
12357
12651
  completed_at: { type: "string", description: "ISO timestamp when the run completed" },
12358
12652
  run_status: { type: "string", enum: ["pending", "running", "completed", "failed", "canceled"], description: "Current execution status of the run" },
12359
12653
  triggering_event: { type: "string", description: "Event or action that triggered this run" },
12360
- step_count: { type: "number", description: "Number of steps executed in this run" },
12654
+ step_count: { type: "number", description: "Number of steps executed in this run", modifier: "derived" },
12361
12655
  total_tokens: { type: "number", description: "Total tokens consumed across all steps" },
12362
12656
  total_cost: { type: "number", description: "Total monetary cost of the run" },
12363
12657
  error_message: { type: "string", description: "Error message if the run failed" }
@@ -12365,8 +12659,8 @@ var UPG_PROPERTY_SCHEMA = {
12365
12659
  // WorkflowTemplateProperties: Workflow template.
12366
12660
  workflow_template: {
12367
12661
  template_type: { type: "string", enum: ["sequential", "parallel", "conditional", "loop"], description: "Execution pattern for the workflow steps" },
12368
- step_count: { type: "number", description: "Number of steps in the workflow" },
12369
- agent_count: { type: "number", description: "Number of agents involved in the workflow" },
12662
+ step_count: { type: "number", description: "Number of steps in the workflow", modifier: "derived" },
12663
+ agent_count: { type: "number", description: "Number of agents involved in the workflow", modifier: "derived" },
12370
12664
  estimated_duration: { type: "string", description: "Estimated wall-clock duration of a full run" },
12371
12665
  state_schema: { type: "string", description: "Schema describing the workflow's state object" },
12372
12666
  checkpoint_enabled: { type: "boolean", description: "Whether the workflow supports checkpointing for recovery" },
@@ -18865,6 +19159,8 @@ var ENTITY_EMOJI = {
18865
19159
  pricing_strategy: "\u{1F4B1}",
18866
19160
  pricing_tier: "\u{1F949}",
18867
19161
  primitive: "\u{1F4CB}",
19162
+ operating_lifecycle: "\u{1F504}",
19163
+ operating_stage: "\u{1F539}",
18868
19164
  privacy_policy: "\u{1F6E1}\uFE0F",
18869
19165
  product: "\u{1F9EC}",
18870
19166
  product_area: "\u{1FA80}",
@@ -22677,7 +22973,7 @@ var WORKSPACE_GUIDE = {
22677
22973
  var FOUNDATIONS_GUIDE = {
22678
22974
  domain_id: "foundations",
22679
22975
  anchor_entity: "specification",
22680
- creation_sequence: ["specification", "primitive"],
22976
+ creation_sequence: ["specification", "primitive", "operating_lifecycle", "operating_stage"],
22681
22977
  patterns: [
22682
22978
  {
22683
22979
  name: "Specification defines primitives",
@@ -26044,6 +26340,7 @@ var UPG_REGIONS = [
26044
26340
  "persona_experiences_need",
26045
26341
  "persona_aspires_to_desired_outcome",
26046
26342
  "persona_incurs_switching_cost",
26343
+ "persona_delegates_to_persona",
26047
26344
  "job_surfaces_need"
26048
26345
  ],
26049
26346
  boundary_edges: [
@@ -28063,6 +28360,14 @@ var UPG_REGIONS = [
28063
28360
  {
28064
28361
  type: "primitive",
28065
28362
  role: "container"
28363
+ },
28364
+ {
28365
+ type: "operating_lifecycle",
28366
+ role: "container"
28367
+ },
28368
+ {
28369
+ type: "operating_stage",
28370
+ role: "leaf"
28066
28371
  }
28067
28372
  ],
28068
28373
  anchor: {
@@ -28075,9 +28380,21 @@ var UPG_REGIONS = [
28075
28380
  "specification_extends_specification",
28076
28381
  "specification_competes_with_specification",
28077
28382
  "primitive_defined_by_specification",
28078
- "primitive_composes_primitive"
28383
+ "primitive_composes_primitive",
28384
+ "operating_lifecycle_contains_operating_stage"
28079
28385
  ],
28080
- boundary_edges: []
28386
+ boundary_edges: [
28387
+ {
28388
+ direction: "import",
28389
+ edge_id: "journey_phase_realises_operating_stage",
28390
+ crosses_into: "experience_design_brand"
28391
+ },
28392
+ {
28393
+ direction: "export",
28394
+ edge_id: "operating_stage_measured_by_metric",
28395
+ crosses_into: "analytics_data"
28396
+ }
28397
+ ]
28081
28398
  }
28082
28399
  ];
28083
28400
  var UPG_REGION_MAP = Object.fromEntries(UPG_REGIONS.map((r) => [r.id, r]));
@@ -28603,7 +28920,7 @@ function isCanonical(text) {
28603
28920
  }
28604
28921
 
28605
28922
  // src/index.ts
28606
- var UPG_VERSION = "0.11.5";
28923
+ var UPG_VERSION = "0.12.0";
28607
28924
  var UPG_FORMAT_VERSION = "0.4.0";
28608
28925
  var MARKDOWN_FORMAT_VERSION = "0.1";
28609
28926
  var UPG_TYPES = getTypes();
@@ -28737,6 +29054,7 @@ export {
28737
29054
  UPG_REGION_COUNT,
28738
29055
  UPG_REGION_MAP,
28739
29056
  UPG_RELATIONSHIP_BENCHMARKS,
29057
+ UPG_SCALAR_TO_EDGE_MIGRATIONS,
28740
29058
  UPG_SCALES,
28741
29059
  UPG_SPLIT_MIGRATIONS,
28742
29060
  UPG_STATUS_MIGRATIONS,
@@ -28805,6 +29123,7 @@ export {
28805
29123
  getRegionForEntityType,
28806
29124
  getReplacementType,
28807
29125
  getRingForDomain,
29126
+ getScalarToEdgeMigrations,
28808
29127
  getScale,
28809
29128
  getSplitMigrations,
28810
29129
  getTreePattern,