@unified-product-graph/core 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +1 -1
- package/dist/index.cjs +188 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +165 -11
- package/dist/index.d.ts +165 -11
- package/dist/index.js +188 -13
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -92,7 +92,7 @@ var UPG_DOMAINS = [
|
|
|
92
92
|
{
|
|
93
93
|
id: "product_spec",
|
|
94
94
|
label: "Product Specification",
|
|
95
|
-
description: "What you are building and shipping. Feature areas group related capabilities. Features, epics, and user stories break work down. Acceptance criteria define done. Tasks and bugs track execution. Releases and changelogs mark what shipped. Roadmaps and roadmap items plan what comes next. Roadmap themes group roadmap work around the customer problem it solves, one level down from the strategic themes in Strategy. Translates Strategy into Engineering and tracks delivery through Program Management.",
|
|
95
|
+
description: "What you are building and shipping. Feature areas group related capabilities. Features, epics, and user stories break work down. Acceptance criteria define done. Tasks and bugs track execution. Releases and changelogs mark what shipped. Roadmaps and roadmap items plan what comes next. Roadmap themes group roadmap work around the customer problem it solves, one level down from the strategic themes in Strategy. Planning cycles are the cadence axis: the named, dated, self-nesting intervals (sprint, iteration, quarter, program increment, cooldown) that work is scheduled through. Translates Strategy into Engineering and tracks delivery through Program Management.",
|
|
96
96
|
types: [
|
|
97
97
|
"feature",
|
|
98
98
|
"feature_area",
|
|
@@ -105,7 +105,8 @@ var UPG_DOMAINS = [
|
|
|
105
105
|
"roadmap",
|
|
106
106
|
"roadmap_item",
|
|
107
107
|
"roadmap_theme",
|
|
108
|
-
"changelog"
|
|
108
|
+
"changelog",
|
|
109
|
+
"planning_cycle"
|
|
109
110
|
]
|
|
110
111
|
},
|
|
111
112
|
{
|
|
@@ -683,6 +684,14 @@ var UPG_ENTITY_META = [
|
|
|
683
684
|
{ name: "theme", type_id: "ent_080", maturity: "deprecated", since: "0.1.0", deprecated_in: "0.9.0", replacement: "roadmap_theme" },
|
|
684
685
|
{ name: "roadmap_theme", type_id: "ent_351", maturity: "stable", since: "0.1.0" },
|
|
685
686
|
{ name: "changelog", type_id: "ent_081", maturity: "stable", since: "0.1.0" },
|
|
687
|
+
// (0.20.0) The cadence axis: a named, dated interval that work flows through
|
|
688
|
+
// and which nests (a program-increment contains iterations; a cycle contains
|
|
689
|
+
// its cooldown). One self-nesting type with a `cadence_kind` discriminator
|
|
690
|
+
// spans sprint / iteration / quarter / PI / cooldown rather than minting a
|
|
691
|
+
// type per methodology. `portfolio_shared` because a coarse cycle is an
|
|
692
|
+
// org-shared interval an objective in a rollup graph and a story in a product
|
|
693
|
+
// graph both schedule into.
|
|
694
|
+
{ name: "planning_cycle", type_id: "ent_358", maturity: "proposed", since: "0.20.0", portfolio_shared: true },
|
|
686
695
|
// ── Engineering ──
|
|
687
696
|
{ name: "bounded_context", type_id: "ent_082", maturity: "stable", since: "0.1.0" },
|
|
688
697
|
{ name: "service", type_id: "ent_083", maturity: "stable", since: "0.1.0" },
|
|
@@ -1299,6 +1308,10 @@ var UPG_EDGE_CATALOG = {
|
|
|
1299
1308
|
strategic_pillar_enables_capability: { forward_verb: "enables", reverse_verb: "enabled_by", classification: "hierarchy", source_type: "strategic_pillar", target_type: "capability" },
|
|
1300
1309
|
strategic_pillar_delivers_value_stream: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "hierarchy", source_type: "strategic_pillar", target_type: "value_stream" },
|
|
1301
1310
|
strategic_pillar_decided_via_decision: { forward_verb: "decided_via", reverse_verb: "decided_for", classification: "hierarchy", source_type: "strategic_pillar", target_type: "decision" },
|
|
1311
|
+
// 0.20.1: the durable pillar's own north-star, mirroring objective_measured_by_metric
|
|
1312
|
+
// one level up the cascade. A strategic_pillar is multi-year and org-wide, so its
|
|
1313
|
+
// measuring metric is portfolio-shared just like the pillar itself.
|
|
1314
|
+
strategic_pillar_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "strategic_pillar", target_type: "metric", cross_product_eligible: true },
|
|
1302
1315
|
strategic_theme_pursues_initiative: { forward_verb: "pursues", reverse_verb: "pursued_under", classification: "hierarchy", source_type: "strategic_theme", target_type: "initiative", cross_product_eligible: true },
|
|
1303
1316
|
// v0.9.0 (UPG-660): the soft bridge from the annual strategy focus area to the
|
|
1304
1317
|
// roadmap grouping that realises it. Semantic, NOT hierarchy: strategic_theme and
|
|
@@ -1331,6 +1344,17 @@ var UPG_EDGE_CATALOG = {
|
|
|
1331
1344
|
strategic_theme_measured_by_key_result: { forward_verb: "measured_by", reverse_verb: "measures", classification: "causal", source_type: "strategic_theme", target_type: "key_result", cross_product_eligible: true },
|
|
1332
1345
|
strategic_theme_contains_objective: { forward_verb: "contains", reverse_verb: "rolls_up_to", classification: "hierarchy", source_type: "strategic_theme", target_type: "objective", cross_product_eligible: true },
|
|
1333
1346
|
initiative_assumes_assumption: { forward_verb: "assumes", reverse_verb: "assumed_by", classification: "hierarchy", source_type: "initiative", target_type: "assumption" },
|
|
1347
|
+
// 0.20.1: the G6 alignment-sheet bridge edges — an initiative reaches directly
|
|
1348
|
+
// into the OKR ladder and the roadmap, rather than only via its parent
|
|
1349
|
+
// strategic_theme. `advances_key_result` is intra-strategy execution (both
|
|
1350
|
+
// ends sit in the strategy domain), so causal not cross-domain; the KR is
|
|
1351
|
+
// portfolio-shared like the initiative, so the pair is cross-product-eligible.
|
|
1352
|
+
initiative_advances_key_result: { forward_verb: "advances", reverse_verb: "advanced_by", classification: "causal", source_type: "initiative", target_type: "key_result", cross_product_eligible: true },
|
|
1353
|
+
// `delivered_via_roadmap_theme` mirrors strategic_theme_realised_by_roadmap_theme:
|
|
1354
|
+
// a semantic cross-reference between the strategy spine and the roadmap spine,
|
|
1355
|
+
// not containment. roadmap_theme is not portfolio-shared, so this stays
|
|
1356
|
+
// within-graph (no cross_product_eligible flag).
|
|
1357
|
+
initiative_delivered_via_roadmap_theme: { forward_verb: "delivered_via", reverse_verb: "delivers", classification: "semantic", source_type: "initiative", target_type: "roadmap_theme" },
|
|
1334
1358
|
initiative_drives_outcome: { forward_verb: "drives", reverse_verb: "driven_by", classification: "cross-domain", source_type: "initiative", target_type: "outcome", cross_product_eligible: true },
|
|
1335
1359
|
capability_enables_value_stream: { forward_verb: "enables", reverse_verb: "enabled_by", classification: "cross-domain", source_type: "capability", target_type: "value_stream" },
|
|
1336
1360
|
// v0.5.2 (UPG-528): three capability-anchored edges that complete the
|
|
@@ -1366,6 +1390,8 @@ var UPG_EDGE_CATALOG = {
|
|
|
1366
1390
|
product_builds_feature: { forward_verb: "builds", reverse_verb: "built_by", classification: "hierarchy", source_type: "product", target_type: "feature" },
|
|
1367
1391
|
product_ships_via_release: { forward_verb: "ships_via", reverse_verb: "ships", classification: "hierarchy", source_type: "product", target_type: "release" },
|
|
1368
1392
|
product_plans_via_roadmap: { forward_verb: "plans_via", reverse_verb: "plans_for", classification: "hierarchy", source_type: "product", target_type: "roadmap" },
|
|
1393
|
+
// (0.20.0) top-level attach for the cadence axis, mirroring product_plans_via_roadmap.
|
|
1394
|
+
product_runs_planning_cycle: { forward_verb: "runs", reverse_verb: "run_by", classification: "hierarchy", source_type: "product", target_type: "planning_cycle" },
|
|
1369
1395
|
product_categorises_by_roadmap_theme: { forward_verb: "categorises_by", reverse_verb: "categorises", classification: "hierarchy", source_type: "product", target_type: "roadmap_theme" },
|
|
1370
1396
|
feature_area_contains_feature: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "feature_area", target_type: "feature" },
|
|
1371
1397
|
feature_area_contains_feature_area: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "feature_area", target_type: "feature_area" },
|
|
@@ -1404,6 +1430,33 @@ var UPG_EDGE_CATALOG = {
|
|
|
1404
1430
|
roadmap_item_references_feature: { forward_verb: "references", reverse_verb: "referenced_by", classification: "cross-domain", source_type: "roadmap_item", target_type: "feature" },
|
|
1405
1431
|
feature_decomposes_into_task: { forward_verb: "decomposes_into", reverse_verb: "implements", classification: "hierarchy", source_type: "feature", target_type: "task" },
|
|
1406
1432
|
task_has_subtask: { forward_verb: "has_subtask", reverse_verb: "is_subtask_of", classification: "hierarchy", source_type: "task", target_type: "task" },
|
|
1433
|
+
// ── Planning cadence (0.20.0) ────────────────────────────────────────────────
|
|
1434
|
+
// The cadence axis. E1 self-nests the interval (a program-increment contains
|
|
1435
|
+
// iterations; a cycle contains its cooldown), mirroring team_contains_team.
|
|
1436
|
+
planning_cycle_contains_planning_cycle: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "planning_cycle", target_type: "planning_cycle" },
|
|
1437
|
+
// E3: scheduling work into a cycle is a deliberate authoring act, not a
|
|
1438
|
+
// containment nesting — user_story keeps its feature/epic parent and is merely
|
|
1439
|
+
// referenced by the cycle. deliberate_only so the generic-inference chokepoints
|
|
1440
|
+
// never auto-materialise it.
|
|
1441
|
+
planning_cycle_schedules_user_story: { forward_verb: "schedules", reverse_verb: "scheduled_in", classification: "semantic", source_type: "planning_cycle", target_type: "user_story", deliberate_only: true },
|
|
1442
|
+
// E2: the OKR cycle-scoping anchor. objective -> planning_cycle. planning_cycle
|
|
1443
|
+
// is portfolio_shared, so this passes the cross-scope gate and ships as
|
|
1444
|
+
// PROVISIONAL (allowed cross-product with a write-time warning, self-maintaining,
|
|
1445
|
+
// never added to the curated set) rather than carrying a cross_product_eligible
|
|
1446
|
+
// flag, which would make it curated. Eligibility is permission, not obligation.
|
|
1447
|
+
objective_scoped_to_planning_cycle: { forward_verb: "scoped_to", reverse_verb: "scopes", classification: "semantic", source_type: "objective", target_type: "planning_cycle" },
|
|
1448
|
+
// F: the promoted `strategic_theme.time_horizon`. Same shape as E2 — a theme's
|
|
1449
|
+
// bounded period becomes a scoping edge onto a shared, dated, nestable interval.
|
|
1450
|
+
// Provisional (planning_cycle portfolio_shared). The property stays @deprecated.
|
|
1451
|
+
strategic_theme_scoped_to_planning_cycle: { forward_verb: "scoped_to", reverse_verb: "scopes", classification: "semantic", source_type: "strategic_theme", target_type: "planning_cycle" },
|
|
1452
|
+
// Gap 2 — polymorphic issue links over the work-item set {feature, epic,
|
|
1453
|
+
// user_story, task, bug}. Endpoint-polymorphic (node -> node, registered in
|
|
1454
|
+
// UPG_POLYMORPHIC_EDGE_KEYS) so one edge covers every level teams link at; the
|
|
1455
|
+
// `work_item_` key names the intended semantic domain. All deliberate_only: an
|
|
1456
|
+
// issue link is authored, never inferred from hierarchy.
|
|
1457
|
+
work_item_blocks_work_item: { forward_verb: "blocks", reverse_verb: "blocked_by", classification: "causal", source_type: "node", target_type: "node", deliberate_only: true },
|
|
1458
|
+
work_item_relates_to_work_item: { forward_verb: "relates_to", reverse_verb: "relates_to", classification: "semantic", source_type: "node", target_type: "node", deliberate_only: true },
|
|
1459
|
+
work_item_duplicates_work_item: { forward_verb: "duplicates", reverse_verb: "duplicated_by", classification: "semantic", source_type: "node", target_type: "node", deliberate_only: true },
|
|
1407
1460
|
// 2.3 Legal Domain
|
|
1408
1461
|
product_owned_by_legal_entity: { forward_verb: "owned_by", reverse_verb: "owns", classification: "hierarchy", source_type: "product", target_type: "legal_entity" },
|
|
1409
1462
|
legal_entity_protects_ip_asset: { forward_verb: "protects", reverse_verb: "protected_by", classification: "hierarchy", source_type: "legal_entity", target_type: "ip_asset" },
|
|
@@ -3187,7 +3240,13 @@ var UPG_POLYMORPHIC_EDGE_KEYS = [
|
|
|
3187
3240
|
// Framework exercises (an exercise can include any entity type)
|
|
3188
3241
|
"framework_exercise_includes_node",
|
|
3189
3242
|
// Universal classification (any node classified against a classification_value)
|
|
3190
|
-
"node_classified_as_classification_value"
|
|
3243
|
+
"node_classified_as_classification_value",
|
|
3244
|
+
// Work-item issue links (0.20.0): endpoint-polymorphic over the work-item set
|
|
3245
|
+
// {feature, epic, user_story, task, bug}. The `work_item_` key names the
|
|
3246
|
+
// intended semantic domain; the endpoints are the `node` wildcard.
|
|
3247
|
+
"work_item_blocks_work_item",
|
|
3248
|
+
"work_item_relates_to_work_item",
|
|
3249
|
+
"work_item_duplicates_work_item"
|
|
3191
3250
|
];
|
|
3192
3251
|
var _POLY_KEY_SET = new Set(UPG_POLYMORPHIC_EDGE_KEYS);
|
|
3193
3252
|
function isPolymorphicEdge(key) {
|
|
@@ -3377,6 +3436,7 @@ var UPG_VALID_CHILDREN = {
|
|
|
3377
3436
|
"release",
|
|
3378
3437
|
"roadmap",
|
|
3379
3438
|
"roadmap_theme",
|
|
3439
|
+
"planning_cycle",
|
|
3380
3440
|
// Engineering
|
|
3381
3441
|
"bounded_context",
|
|
3382
3442
|
"code_repository",
|
|
@@ -3554,7 +3614,11 @@ var UPG_VALID_CHILDREN = {
|
|
|
3554
3614
|
// That success-measurement asymmetry is the load-bearing distinction.
|
|
3555
3615
|
vision: ["mission"],
|
|
3556
3616
|
mission: ["strategic_pillar"],
|
|
3557
|
-
|
|
3617
|
+
// 0.20.1: metric added as a strategic_pillar child, backing
|
|
3618
|
+
// strategic_pillar_measured_by_metric (hierarchy) — the pillar's own
|
|
3619
|
+
// north-star, mirrored from objective: ['key_result', 'metric', ...] one
|
|
3620
|
+
// level down the cascade.
|
|
3621
|
+
strategic_pillar: ["strategic_theme", "capability", "value_stream", "decision", "metric"],
|
|
3558
3622
|
// v0.5.4 (UPG-511): objectives are the specific quarterly bets *within* a
|
|
3559
3623
|
// strategic theme. The theme is the multi-quarter focus area; objectives are
|
|
3560
3624
|
// subordinate. Pairs with `strategic_theme_contains_objective` in the edge
|
|
@@ -3645,6 +3709,13 @@ var UPG_VALID_CHILDREN = {
|
|
|
3645
3709
|
epic: ["user_story"],
|
|
3646
3710
|
user_story: ["acceptance_criterion"],
|
|
3647
3711
|
task: ["task"],
|
|
3712
|
+
// planning_cycle (0.20.0): the cadence axis self-nests (a program-increment
|
|
3713
|
+
// contains iterations; a cycle contains its cooldown) via
|
|
3714
|
+
// planning_cycle_contains_planning_cycle. It does NOT contain user_story as a
|
|
3715
|
+
// child: scheduling work into a cycle is the semantic, deliberate-only
|
|
3716
|
+
// planning_cycle_schedules_user_story edge, so a story keeps its feature/epic
|
|
3717
|
+
// containment parent and is merely referenced by the cycle.
|
|
3718
|
+
planning_cycle: ["planning_cycle"],
|
|
3648
3719
|
// ── Engineering hierarchy ───────────────────────────────────────────────────
|
|
3649
3720
|
bounded_context: [
|
|
3650
3721
|
"service",
|
|
@@ -6288,6 +6359,16 @@ var SPECIFICATION_LIFECYCLE = {
|
|
|
6288
6359
|
}
|
|
6289
6360
|
]
|
|
6290
6361
|
};
|
|
6362
|
+
var PLANNING_CYCLE_LIFECYCLE = {
|
|
6363
|
+
entity_type: "planning_cycle",
|
|
6364
|
+
initial_phase: "planned",
|
|
6365
|
+
terminal_phases: ["closed"],
|
|
6366
|
+
phases: [
|
|
6367
|
+
{ id: "planned", label: "Planned", description: "The cycle is being shaped: dates set, goal written, work scheduled into it. It has not started yet.", transitions_to: ["active"] },
|
|
6368
|
+
{ id: "active", label: "Active", description: "The team is inside the interval; work is flowing through it.", transitions_to: ["closed"] },
|
|
6369
|
+
{ id: "closed", label: "Closed", description: "The interval has ended. Scheduled work has shipped, carried over, or been dropped. May reopen if the team extends or reruns it.", transitions_to: ["active"] }
|
|
6370
|
+
]
|
|
6371
|
+
};
|
|
6291
6372
|
var UPG_LIFECYCLES = [
|
|
6292
6373
|
// Product (root)
|
|
6293
6374
|
PRODUCT_LIFECYCLE,
|
|
@@ -6331,6 +6412,7 @@ var UPG_LIFECYCLES = [
|
|
|
6331
6412
|
TASK_LIFECYCLE,
|
|
6332
6413
|
BUG_LIFECYCLE,
|
|
6333
6414
|
ROADMAP_ITEM_LIFECYCLE,
|
|
6415
|
+
PLANNING_CYCLE_LIFECYCLE,
|
|
6334
6416
|
IP_ASSET_LIFECYCLE,
|
|
6335
6417
|
CONTRACT_LIFECYCLE,
|
|
6336
6418
|
DESIGN_CONCEPT_LIFECYCLE,
|
|
@@ -10513,7 +10595,9 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
10513
10595
|
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)." },
|
|
10514
10596
|
assignee: { type: "string", description: "Assigned person. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
10515
10597
|
due_date: { type: "string", description: "ISO date due. Often tied to a release gate or SLA." },
|
|
10516
|
-
labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." }
|
|
10598
|
+
labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." },
|
|
10599
|
+
workflow_state: { type: "string", description: 'The source tool\'s raw custom workflow state, verbatim and opaque (e.g. "In Review", "QA", "Needs Triage"). Non-canonical and never reasoned over: it exists to round-trip an import losslessly. Map it onto a canonical bucket with `workflow_state_category`; canonical `status` stays the sole reasoning axis.' },
|
|
10600
|
+
workflow_state_category: { type: "string", description: 'Canonical bucket the raw `workflow_state` maps onto for reasoning (a source "In Review" and "QA" might both map to a verification phase). Optional companion to `workflow_state`: it lets a graph reason over an imported custom workflow without promoting the raw label to `status`.' }
|
|
10517
10601
|
},
|
|
10518
10602
|
// BuildArtifactProperties: Build artifact.
|
|
10519
10603
|
build_artifact: {
|
|
@@ -11167,7 +11251,9 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
11167
11251
|
priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Task-level priority" },
|
|
11168
11252
|
owner: { type: "string", description: "Responsible person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
11169
11253
|
start_date: { type: "string", description: "ISO date work begins" },
|
|
11170
|
-
target_date: { type: "string", description: "ISO date work completes" }
|
|
11254
|
+
target_date: { type: "string", description: "ISO date work completes" },
|
|
11255
|
+
workflow_state: { type: "string", description: 'The source tool\'s raw custom workflow state, verbatim and opaque (e.g. "In Review", "QA", "Needs Triage"). Non-canonical and never reasoned over: it exists to round-trip an import losslessly. Map it onto a canonical bucket with `workflow_state_category`; canonical `status` stays the sole reasoning axis.' },
|
|
11256
|
+
workflow_state_category: { type: "string", description: 'Canonical bucket the raw `workflow_state` maps onto for reasoning (a source "In Review" and "QA" might both map to a verification phase). Optional companion to `workflow_state`: it lets a graph reason over an imported custom workflow without promoting the raw label to `status`.' }
|
|
11171
11257
|
},
|
|
11172
11258
|
// ErrorBudgetProperties: Error budget.
|
|
11173
11259
|
error_budget: {
|
|
@@ -11347,7 +11433,9 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
11347
11433
|
owner: { type: "string", description: "Responsible person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
11348
11434
|
start_date: { type: "string", description: "ISO date work begins" },
|
|
11349
11435
|
target_date: { type: "string", description: "ISO date work completes" },
|
|
11350
|
-
health: { type: "string", enum: ["on_track", "at_risk", "off_track"], description: "Delivery health" }
|
|
11436
|
+
health: { type: "string", enum: ["on_track", "at_risk", "off_track"], description: "Delivery health" },
|
|
11437
|
+
workflow_state: { type: "string", description: 'The source tool\'s raw custom workflow state, verbatim and opaque (e.g. "In Review", "QA", "Needs Triage"). Non-canonical and never reasoned over: it exists to round-trip an import losslessly. Map it onto a canonical bucket with `workflow_state_category`; canonical `status` stays the sole reasoning axis.' },
|
|
11438
|
+
workflow_state_category: { type: "string", description: 'Canonical bucket the raw `workflow_state` maps onto for reasoning (a source "In Review" and "QA" might both map to a verification phase). Optional companion to `workflow_state`: it lets a graph reason over an imported custom workflow without promoting the raw label to `status`.' }
|
|
11351
11439
|
},
|
|
11352
11440
|
// FeatureAreaProperties: A structural grouping of related features within a product.
|
|
11353
11441
|
feature_area: {
|
|
@@ -12267,6 +12355,16 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
12267
12355
|
conversion_rate: { type: "number", description: "Percentage of deals that advance from this stage", modifier: "snapshot" },
|
|
12268
12356
|
avg_days_in_stage: { type: "number", description: "Average number of days deals spend in this stage" }
|
|
12269
12357
|
},
|
|
12358
|
+
// PlanningCycleProperties: Planning cycle: a named, dated interval work flows through, which nests.
|
|
12359
|
+
planning_cycle: {
|
|
12360
|
+
cadence_kind: { type: "string", enum: ["period", "iteration", "buffer"], description: "Methodology-neutral granularity of this interval. `period` is a coarse container (quarter / PI / OKR-cycle scale); `iteration` is a fine execution box (sprint / cycle); `buffer` is between-box slack (cooldown). Required: it is the discriminator that lets one type stand in for every methodology." },
|
|
12361
|
+
cadence_label: { type: "string", description: 'The source methodology term verbatim ("sprint", "cycle", "PI", "quarter", "cooldown"). The dual-band label: `cadence_kind` is the canonical granularity reasoned over; `cadence_label` preserves what the team actually calls it.' },
|
|
12362
|
+
starts_on: { type: "string", description: "ISO date the interval opens. A cycle is concretely dated, unlike a coarse `time_horizon` label." },
|
|
12363
|
+
ends_on: { type: "string", description: "ISO date the interval closes." },
|
|
12364
|
+
sequence: { type: "number", description: "The cycle / iteration number (e.g. Sprint 47, PI 3)." },
|
|
12365
|
+
goal: { type: "string", description: "The interval's goal or focus: what this cadence box is for." },
|
|
12366
|
+
appetite: { type: "string", description: 'Shape Up appetite: the fixed time budget a cycle is willing to spend on a bet (e.g. "6 weeks", "2 weeks").' }
|
|
12367
|
+
},
|
|
12270
12368
|
// PlaybookProperties: Customer success playbook.
|
|
12271
12369
|
playbook: {
|
|
12272
12370
|
playbook_type: { type: "string", enum: ["onboarding", "expansion", "renewal", "rescue", "other"], description: "Scenario this playbook addresses" },
|
|
@@ -12818,7 +12916,7 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
12818
12916
|
// StrategicThemeProperties: StrategicTheme entity.
|
|
12819
12917
|
strategic_theme: {
|
|
12820
12918
|
owner: { type: "string", description: "Owning person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
12821
|
-
time_horizon: { type: "string", description: 'Bounded period this theme is active (a theme is time-bound, within a pillar). @example "Q1 2026", "FY26"' },
|
|
12919
|
+
time_horizon: { type: "string", description: 'Bounded period this theme is active (a theme is time-bound, within a pillar). @deprecated since 0.20.0. Promote the period to a `planning_cycle` node and link it with the `strategic_theme_scoped_to_planning_cycle` edge, which points at a shared, dated, nestable interval instead of a drifting per-theme string. Kept (not removed) for back-compat; removal is a later major. `strategic_pillar.time_horizon` stays as-is (a durable pillar horizon is genuinely open-ended, not a dated cycle). @example "Q1 2026", "FY26"' },
|
|
12822
12920
|
description: { type: "string", description: "Short narrative of this time-bound thrust within its pillar" },
|
|
12823
12921
|
scope: { type: "string", description: "What the theme explicitly includes or excludes" }
|
|
12824
12922
|
},
|
|
@@ -12914,7 +13012,9 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
12914
13012
|
effort: { type: "string", description: 'Effort estimate (e.g. "2h", "1d", "3 points"). Use a consistent unit within your team.' },
|
|
12915
13013
|
priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Relative importance against other tasks" },
|
|
12916
13014
|
due_date: { type: "string", description: "ISO date due. Typically bounded by the containing story's due date." },
|
|
12917
|
-
labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." }
|
|
13015
|
+
labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." },
|
|
13016
|
+
workflow_state: { type: "string", description: 'The source tool\'s raw custom workflow state, verbatim and opaque (e.g. "In Review", "QA", "Needs Triage"). Non-canonical and never reasoned over: it exists to round-trip an import losslessly. Map it onto a canonical bucket with `workflow_state_category`; canonical `status` stays the sole reasoning axis.' },
|
|
13017
|
+
workflow_state_category: { type: "string", description: 'Canonical bucket the raw `workflow_state` maps onto for reasoning (a source "In Review" and "QA" might both map to a verification phase). Optional companion to `workflow_state`: it lets a graph reason over an imported custom workflow without promoting the raw label to `status`.' }
|
|
12918
13018
|
},
|
|
12919
13019
|
// TeamProperties: Team entity.
|
|
12920
13020
|
team: {
|
|
@@ -13129,7 +13229,13 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
13129
13229
|
as_a: { type: "string", description: '"As a [persona], \u2026". Free-text persona name or slug ref.' },
|
|
13130
13230
|
i_want_to: { type: "string", description: "Capability or action the persona wants." },
|
|
13131
13231
|
so_that: { type: "string", description: "Benefit or outcome the persona expects." },
|
|
13132
|
-
text: { type: "string", description: "Free-form story text. Used as a single-line rendered view." }
|
|
13232
|
+
text: { type: "string", description: "Free-form story text. Used as a single-line rendered view." },
|
|
13233
|
+
assignee: { type: "string", description: "Assigned person. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
13234
|
+
effort: { type: "string", description: 'Effort estimate (e.g. "2h", "1d", "3 points"). Use a consistent unit within your team.' },
|
|
13235
|
+
priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Relative importance against other stories. Lifted onto user_story (0.20.0) so the story is a first-class plannable unit alongside task, matching Jira/Linear where the story/issue is the estimated-and-assigned atom." },
|
|
13236
|
+
due_date: { type: "string", description: "ISO date due. Typically bounded by the release or planning_cycle the story is scheduled into." },
|
|
13237
|
+
workflow_state: { type: "string", description: 'The source tool\'s raw custom workflow state, verbatim and opaque (e.g. "In Review", "QA", "Needs Triage"). Non-canonical and never reasoned over: it exists to round-trip an import losslessly. Map it onto a canonical bucket with `workflow_state_category`; canonical `status` stays the sole reasoning axis.' },
|
|
13238
|
+
workflow_state_category: { type: "string", description: 'Canonical bucket the raw `workflow_state` maps onto for reasoning (a source "In Review" and "QA" might both map to a verification phase). Optional companion to `workflow_state`: it lets a graph reason over an imported custom workflow without promoting the raw label to `status`.' }
|
|
13133
13239
|
},
|
|
13134
13240
|
// ValueObjectProperties: DDD value object.
|
|
13135
13241
|
value_object: {
|
|
@@ -19775,6 +19881,7 @@ var ENTITY_EMOJI = {
|
|
|
19775
19881
|
persona: "\u{1F3AD}",
|
|
19776
19882
|
pipeline_sales: "\u{1FA88}",
|
|
19777
19883
|
pipeline_stage: "\u{1F9FD}",
|
|
19884
|
+
planning_cycle: "\u{1F5D3}\uFE0F",
|
|
19778
19885
|
playbook: "\u{1F4D2}",
|
|
19779
19886
|
portfolio: "\u{1F9F8}",
|
|
19780
19887
|
positioning: "\u{1F3AA}",
|
|
@@ -20466,6 +20573,7 @@ var STANDARD_LABELS = {
|
|
|
20466
20573
|
roadmap_item: { alt_labels: ["roadmap entry", "planned item"] },
|
|
20467
20574
|
roadmap_theme: { alt_labels: ["product theme", "roadmap theme"] },
|
|
20468
20575
|
// UPG-660: renamed from bare 'theme' (N6 lineage)
|
|
20576
|
+
planning_cycle: { alt_labels: ["sprint", "iteration", "cycle", "program increment", "pi", "cadence", "time-box", "cooldown", "quarter"] },
|
|
20469
20577
|
// Engineering layer
|
|
20470
20578
|
bounded_context: { alt_labels: ["context", "domain boundary", "module boundary"] },
|
|
20471
20579
|
service: { alt_labels: ["microservice", "backend service", "api service"] },
|
|
@@ -22987,13 +23095,19 @@ var PRODUCT_SPEC_GUIDE = {
|
|
|
22987
23095
|
// registered to product_spec but missing from the navigation order).
|
|
22988
23096
|
// `changelog` lives here because it is a structural product-shipping
|
|
22989
23097
|
// artefact; content domain references it only via cross-domain bridges.
|
|
22990
|
-
creation_sequence: ["feature_area", "feature", "epic", "user_story", "acceptance_criterion", "task", "bug", "release", "roadmap", "roadmap_item", "roadmap_theme", "changelog"],
|
|
23098
|
+
creation_sequence: ["feature_area", "feature", "epic", "user_story", "acceptance_criterion", "task", "bug", "release", "roadmap", "roadmap_item", "roadmap_theme", "changelog", "planning_cycle"],
|
|
22991
23099
|
patterns: [
|
|
22992
23100
|
{
|
|
22993
23101
|
name: "Feature Decomposition",
|
|
22994
23102
|
description: "Features group into areas, decompose into epics, epics specify user stories (the templated promise), and tasks implement them as the engineering work",
|
|
22995
23103
|
entity_types: ["feature_area", "feature", "epic", "user_story", "task"],
|
|
22996
23104
|
edge_chain: ["feature_area_contains_feature", "feature_decomposed_into_epic", "epic_specified_by_user_story", "task_implements_user_story"]
|
|
23105
|
+
},
|
|
23106
|
+
{
|
|
23107
|
+
name: "Planning Cadence",
|
|
23108
|
+
description: "The cadence axis. Create a planning_cycle (a sprint, iteration, quarter, or PI), nest finer cycles inside a coarse one, schedule the stories that flow through it, and scope the objectives the cycle serves. Scheduling and scoping are deliberate links, not containment: a story keeps its feature/epic parent.",
|
|
23109
|
+
entity_types: ["planning_cycle", "user_story", "objective"],
|
|
23110
|
+
edge_chain: ["planning_cycle_contains_planning_cycle", "planning_cycle_schedules_user_story", "objective_scoped_to_planning_cycle"]
|
|
22997
23111
|
}
|
|
22998
23112
|
],
|
|
22999
23113
|
required_bridges: [
|
|
@@ -26262,6 +26376,40 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26262
26376
|
severity: "high",
|
|
26263
26377
|
source: { kind: "practitioner", attribution: "John Cutler, Outcomes over Output" }
|
|
26264
26378
|
},
|
|
26379
|
+
{
|
|
26380
|
+
id: "planning-cycle-without-scheduled-work",
|
|
26381
|
+
name: "Planning cycle with no scheduled work",
|
|
26382
|
+
description: "A planning_cycle exists but neither schedules any user_story nor contains a finer sub-cycle. An empty cadence box is a date range with nothing flowing through it: a sprint or iteration nobody planned work into, or a coarse period that was never broken down.",
|
|
26383
|
+
structured_condition: {
|
|
26384
|
+
operator: "and",
|
|
26385
|
+
checks: [
|
|
26386
|
+
{ check: { type: "entity_count", entity_type: "planning_cycle", comparison: "nonzero" } },
|
|
26387
|
+
{
|
|
26388
|
+
check: {
|
|
26389
|
+
type: "relationship",
|
|
26390
|
+
source_type: "planning_cycle",
|
|
26391
|
+
edge_type: "planning_cycle_schedules_user_story",
|
|
26392
|
+
target_type: "user_story",
|
|
26393
|
+
comparison: "not_exists"
|
|
26394
|
+
}
|
|
26395
|
+
},
|
|
26396
|
+
{
|
|
26397
|
+
check: {
|
|
26398
|
+
type: "relationship",
|
|
26399
|
+
source_type: "planning_cycle",
|
|
26400
|
+
edge_type: "planning_cycle_contains_planning_cycle",
|
|
26401
|
+
target_type: "planning_cycle",
|
|
26402
|
+
comparison: "not_exists"
|
|
26403
|
+
}
|
|
26404
|
+
}
|
|
26405
|
+
]
|
|
26406
|
+
},
|
|
26407
|
+
why_it_matters: "A cadence layer only earns its keep when work is planned through it. An interval with no scheduled stories and no nested cycles adds ceremony without telling anyone what the period is for.",
|
|
26408
|
+
remediation: "Schedule the stories the cycle will carry via `planning_cycle_schedules_user_story`, or break a coarse period into finer cycles via `planning_cycle_contains_planning_cycle`. If neither applies, the interval is not yet a real cadence box.",
|
|
26409
|
+
stages: ["build", "beta", "launch", "growth", "mature"],
|
|
26410
|
+
severity: "low",
|
|
26411
|
+
since: "0.20.0"
|
|
26412
|
+
},
|
|
26265
26413
|
// ── Market intelligence layer ───────────────────────────────────────────
|
|
26266
26414
|
{
|
|
26267
26415
|
id: "competitors-missing-past-validation",
|
|
@@ -27090,6 +27238,16 @@ var UPG_REGIONS = [
|
|
|
27090
27238
|
edge_id: "outcome_delivered_via_feature_area",
|
|
27091
27239
|
crosses_into: "product_delivery"
|
|
27092
27240
|
},
|
|
27241
|
+
{
|
|
27242
|
+
direction: "export",
|
|
27243
|
+
edge_id: "objective_scoped_to_planning_cycle",
|
|
27244
|
+
crosses_into: "product_delivery"
|
|
27245
|
+
},
|
|
27246
|
+
{
|
|
27247
|
+
direction: "export",
|
|
27248
|
+
edge_id: "strategic_theme_scoped_to_planning_cycle",
|
|
27249
|
+
crosses_into: "product_delivery"
|
|
27250
|
+
},
|
|
27093
27251
|
{
|
|
27094
27252
|
direction: "import",
|
|
27095
27253
|
edge_id: "feature_drives_key_result",
|
|
@@ -27901,6 +28059,11 @@ var UPG_REGIONS = [
|
|
|
27901
28059
|
{
|
|
27902
28060
|
type: "status_report",
|
|
27903
28061
|
role: "leaf"
|
|
28062
|
+
},
|
|
28063
|
+
{
|
|
28064
|
+
type: "planning_cycle",
|
|
28065
|
+
role: "container",
|
|
28066
|
+
notes: "self-nesting cadence axis"
|
|
27904
28067
|
}
|
|
27905
28068
|
],
|
|
27906
28069
|
anchor: {
|
|
@@ -27924,7 +28087,9 @@ var UPG_REGIONS = [
|
|
|
27924
28087
|
"roadmap_theme_spans_feature_area",
|
|
27925
28088
|
"milestone_gates_release",
|
|
27926
28089
|
"roadmap_item_references_feature",
|
|
27927
|
-
"feature_request_voted_on_by_feedback_vote"
|
|
28090
|
+
"feature_request_voted_on_by_feedback_vote",
|
|
28091
|
+
"planning_cycle_contains_planning_cycle",
|
|
28092
|
+
"planning_cycle_schedules_user_story"
|
|
27928
28093
|
],
|
|
27929
28094
|
boundary_edges: [
|
|
27930
28095
|
{
|
|
@@ -27932,6 +28097,16 @@ var UPG_REGIONS = [
|
|
|
27932
28097
|
edge_id: "outcome_delivered_by_feature",
|
|
27933
28098
|
crosses_into: "strategy_outcomes"
|
|
27934
28099
|
},
|
|
28100
|
+
{
|
|
28101
|
+
direction: "import",
|
|
28102
|
+
edge_id: "objective_scoped_to_planning_cycle",
|
|
28103
|
+
crosses_into: "strategy_outcomes"
|
|
28104
|
+
},
|
|
28105
|
+
{
|
|
28106
|
+
direction: "import",
|
|
28107
|
+
edge_id: "strategic_theme_scoped_to_planning_cycle",
|
|
28108
|
+
crosses_into: "strategy_outcomes"
|
|
28109
|
+
},
|
|
27935
28110
|
{
|
|
27936
28111
|
direction: "import",
|
|
27937
28112
|
edge_id: "outcome_delivered_via_feature_area",
|
|
@@ -29744,7 +29919,7 @@ function isCanonical(text) {
|
|
|
29744
29919
|
}
|
|
29745
29920
|
|
|
29746
29921
|
// src/index.ts
|
|
29747
|
-
var UPG_VERSION = "0.
|
|
29922
|
+
var UPG_VERSION = "0.20.1";
|
|
29748
29923
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
29749
29924
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
29750
29925
|
var UPG_TYPES = getTypes();
|