@unified-product-graph/core 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +335 -0
- package/README.md +1 -1
- package/dist/index.cjs +168 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +135 -6
- package/dist/index.d.ts +135 -6
- package/dist/index.js +168 -12
- 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" },
|
|
@@ -1366,6 +1375,8 @@ var UPG_EDGE_CATALOG = {
|
|
|
1366
1375
|
product_builds_feature: { forward_verb: "builds", reverse_verb: "built_by", classification: "hierarchy", source_type: "product", target_type: "feature" },
|
|
1367
1376
|
product_ships_via_release: { forward_verb: "ships_via", reverse_verb: "ships", classification: "hierarchy", source_type: "product", target_type: "release" },
|
|
1368
1377
|
product_plans_via_roadmap: { forward_verb: "plans_via", reverse_verb: "plans_for", classification: "hierarchy", source_type: "product", target_type: "roadmap" },
|
|
1378
|
+
// (0.20.0) top-level attach for the cadence axis, mirroring product_plans_via_roadmap.
|
|
1379
|
+
product_runs_planning_cycle: { forward_verb: "runs", reverse_verb: "run_by", classification: "hierarchy", source_type: "product", target_type: "planning_cycle" },
|
|
1369
1380
|
product_categorises_by_roadmap_theme: { forward_verb: "categorises_by", reverse_verb: "categorises", classification: "hierarchy", source_type: "product", target_type: "roadmap_theme" },
|
|
1370
1381
|
feature_area_contains_feature: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "feature_area", target_type: "feature" },
|
|
1371
1382
|
feature_area_contains_feature_area: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "feature_area", target_type: "feature_area" },
|
|
@@ -1404,6 +1415,33 @@ var UPG_EDGE_CATALOG = {
|
|
|
1404
1415
|
roadmap_item_references_feature: { forward_verb: "references", reverse_verb: "referenced_by", classification: "cross-domain", source_type: "roadmap_item", target_type: "feature" },
|
|
1405
1416
|
feature_decomposes_into_task: { forward_verb: "decomposes_into", reverse_verb: "implements", classification: "hierarchy", source_type: "feature", target_type: "task" },
|
|
1406
1417
|
task_has_subtask: { forward_verb: "has_subtask", reverse_verb: "is_subtask_of", classification: "hierarchy", source_type: "task", target_type: "task" },
|
|
1418
|
+
// ── Planning cadence (0.20.0) ────────────────────────────────────────────────
|
|
1419
|
+
// The cadence axis. E1 self-nests the interval (a program-increment contains
|
|
1420
|
+
// iterations; a cycle contains its cooldown), mirroring team_contains_team.
|
|
1421
|
+
planning_cycle_contains_planning_cycle: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "planning_cycle", target_type: "planning_cycle" },
|
|
1422
|
+
// E3: scheduling work into a cycle is a deliberate authoring act, not a
|
|
1423
|
+
// containment nesting — user_story keeps its feature/epic parent and is merely
|
|
1424
|
+
// referenced by the cycle. deliberate_only so the generic-inference chokepoints
|
|
1425
|
+
// never auto-materialise it.
|
|
1426
|
+
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 },
|
|
1427
|
+
// E2: the OKR cycle-scoping anchor. objective -> planning_cycle. planning_cycle
|
|
1428
|
+
// is portfolio_shared, so this passes the cross-scope gate and ships as
|
|
1429
|
+
// PROVISIONAL (allowed cross-product with a write-time warning, self-maintaining,
|
|
1430
|
+
// never added to the curated set) rather than carrying a cross_product_eligible
|
|
1431
|
+
// flag, which would make it curated. Eligibility is permission, not obligation.
|
|
1432
|
+
objective_scoped_to_planning_cycle: { forward_verb: "scoped_to", reverse_verb: "scopes", classification: "semantic", source_type: "objective", target_type: "planning_cycle" },
|
|
1433
|
+
// F: the promoted `strategic_theme.time_horizon`. Same shape as E2 — a theme's
|
|
1434
|
+
// bounded period becomes a scoping edge onto a shared, dated, nestable interval.
|
|
1435
|
+
// Provisional (planning_cycle portfolio_shared). The property stays @deprecated.
|
|
1436
|
+
strategic_theme_scoped_to_planning_cycle: { forward_verb: "scoped_to", reverse_verb: "scopes", classification: "semantic", source_type: "strategic_theme", target_type: "planning_cycle" },
|
|
1437
|
+
// Gap 2 — polymorphic issue links over the work-item set {feature, epic,
|
|
1438
|
+
// user_story, task, bug}. Endpoint-polymorphic (node -> node, registered in
|
|
1439
|
+
// UPG_POLYMORPHIC_EDGE_KEYS) so one edge covers every level teams link at; the
|
|
1440
|
+
// `work_item_` key names the intended semantic domain. All deliberate_only: an
|
|
1441
|
+
// issue link is authored, never inferred from hierarchy.
|
|
1442
|
+
work_item_blocks_work_item: { forward_verb: "blocks", reverse_verb: "blocked_by", classification: "causal", source_type: "node", target_type: "node", deliberate_only: true },
|
|
1443
|
+
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 },
|
|
1444
|
+
work_item_duplicates_work_item: { forward_verb: "duplicates", reverse_verb: "duplicated_by", classification: "semantic", source_type: "node", target_type: "node", deliberate_only: true },
|
|
1407
1445
|
// 2.3 Legal Domain
|
|
1408
1446
|
product_owned_by_legal_entity: { forward_verb: "owned_by", reverse_verb: "owns", classification: "hierarchy", source_type: "product", target_type: "legal_entity" },
|
|
1409
1447
|
legal_entity_protects_ip_asset: { forward_verb: "protects", reverse_verb: "protected_by", classification: "hierarchy", source_type: "legal_entity", target_type: "ip_asset" },
|
|
@@ -3187,7 +3225,13 @@ var UPG_POLYMORPHIC_EDGE_KEYS = [
|
|
|
3187
3225
|
// Framework exercises (an exercise can include any entity type)
|
|
3188
3226
|
"framework_exercise_includes_node",
|
|
3189
3227
|
// Universal classification (any node classified against a classification_value)
|
|
3190
|
-
"node_classified_as_classification_value"
|
|
3228
|
+
"node_classified_as_classification_value",
|
|
3229
|
+
// Work-item issue links (0.20.0): endpoint-polymorphic over the work-item set
|
|
3230
|
+
// {feature, epic, user_story, task, bug}. The `work_item_` key names the
|
|
3231
|
+
// intended semantic domain; the endpoints are the `node` wildcard.
|
|
3232
|
+
"work_item_blocks_work_item",
|
|
3233
|
+
"work_item_relates_to_work_item",
|
|
3234
|
+
"work_item_duplicates_work_item"
|
|
3191
3235
|
];
|
|
3192
3236
|
var _POLY_KEY_SET = new Set(UPG_POLYMORPHIC_EDGE_KEYS);
|
|
3193
3237
|
function isPolymorphicEdge(key) {
|
|
@@ -3377,6 +3421,7 @@ var UPG_VALID_CHILDREN = {
|
|
|
3377
3421
|
"release",
|
|
3378
3422
|
"roadmap",
|
|
3379
3423
|
"roadmap_theme",
|
|
3424
|
+
"planning_cycle",
|
|
3380
3425
|
// Engineering
|
|
3381
3426
|
"bounded_context",
|
|
3382
3427
|
"code_repository",
|
|
@@ -3645,6 +3690,13 @@ var UPG_VALID_CHILDREN = {
|
|
|
3645
3690
|
epic: ["user_story"],
|
|
3646
3691
|
user_story: ["acceptance_criterion"],
|
|
3647
3692
|
task: ["task"],
|
|
3693
|
+
// planning_cycle (0.20.0): the cadence axis self-nests (a program-increment
|
|
3694
|
+
// contains iterations; a cycle contains its cooldown) via
|
|
3695
|
+
// planning_cycle_contains_planning_cycle. It does NOT contain user_story as a
|
|
3696
|
+
// child: scheduling work into a cycle is the semantic, deliberate-only
|
|
3697
|
+
// planning_cycle_schedules_user_story edge, so a story keeps its feature/epic
|
|
3698
|
+
// containment parent and is merely referenced by the cycle.
|
|
3699
|
+
planning_cycle: ["planning_cycle"],
|
|
3648
3700
|
// ── Engineering hierarchy ───────────────────────────────────────────────────
|
|
3649
3701
|
bounded_context: [
|
|
3650
3702
|
"service",
|
|
@@ -6288,6 +6340,16 @@ var SPECIFICATION_LIFECYCLE = {
|
|
|
6288
6340
|
}
|
|
6289
6341
|
]
|
|
6290
6342
|
};
|
|
6343
|
+
var PLANNING_CYCLE_LIFECYCLE = {
|
|
6344
|
+
entity_type: "planning_cycle",
|
|
6345
|
+
initial_phase: "planned",
|
|
6346
|
+
terminal_phases: ["closed"],
|
|
6347
|
+
phases: [
|
|
6348
|
+
{ 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"] },
|
|
6349
|
+
{ id: "active", label: "Active", description: "The team is inside the interval; work is flowing through it.", transitions_to: ["closed"] },
|
|
6350
|
+
{ 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"] }
|
|
6351
|
+
]
|
|
6352
|
+
};
|
|
6291
6353
|
var UPG_LIFECYCLES = [
|
|
6292
6354
|
// Product (root)
|
|
6293
6355
|
PRODUCT_LIFECYCLE,
|
|
@@ -6331,6 +6393,7 @@ var UPG_LIFECYCLES = [
|
|
|
6331
6393
|
TASK_LIFECYCLE,
|
|
6332
6394
|
BUG_LIFECYCLE,
|
|
6333
6395
|
ROADMAP_ITEM_LIFECYCLE,
|
|
6396
|
+
PLANNING_CYCLE_LIFECYCLE,
|
|
6334
6397
|
IP_ASSET_LIFECYCLE,
|
|
6335
6398
|
CONTRACT_LIFECYCLE,
|
|
6336
6399
|
DESIGN_CONCEPT_LIFECYCLE,
|
|
@@ -10513,7 +10576,9 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
10513
10576
|
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
10577
|
assignee: { type: "string", description: "Assigned person. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
10515
10578
|
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." }
|
|
10579
|
+
labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." },
|
|
10580
|
+
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.' },
|
|
10581
|
+
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
10582
|
},
|
|
10518
10583
|
// BuildArtifactProperties: Build artifact.
|
|
10519
10584
|
build_artifact: {
|
|
@@ -11167,7 +11232,9 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
11167
11232
|
priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Task-level priority" },
|
|
11168
11233
|
owner: { type: "string", description: "Responsible person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
11169
11234
|
start_date: { type: "string", description: "ISO date work begins" },
|
|
11170
|
-
target_date: { type: "string", description: "ISO date work completes" }
|
|
11235
|
+
target_date: { type: "string", description: "ISO date work completes" },
|
|
11236
|
+
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.' },
|
|
11237
|
+
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
11238
|
},
|
|
11172
11239
|
// ErrorBudgetProperties: Error budget.
|
|
11173
11240
|
error_budget: {
|
|
@@ -11347,7 +11414,9 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
11347
11414
|
owner: { type: "string", description: "Responsible person or team. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
11348
11415
|
start_date: { type: "string", description: "ISO date work begins" },
|
|
11349
11416
|
target_date: { type: "string", description: "ISO date work completes" },
|
|
11350
|
-
health: { type: "string", enum: ["on_track", "at_risk", "off_track"], description: "Delivery health" }
|
|
11417
|
+
health: { type: "string", enum: ["on_track", "at_risk", "off_track"], description: "Delivery health" },
|
|
11418
|
+
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.' },
|
|
11419
|
+
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
11420
|
},
|
|
11352
11421
|
// FeatureAreaProperties: A structural grouping of related features within a product.
|
|
11353
11422
|
feature_area: {
|
|
@@ -12267,6 +12336,16 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
12267
12336
|
conversion_rate: { type: "number", description: "Percentage of deals that advance from this stage", modifier: "snapshot" },
|
|
12268
12337
|
avg_days_in_stage: { type: "number", description: "Average number of days deals spend in this stage" }
|
|
12269
12338
|
},
|
|
12339
|
+
// PlanningCycleProperties: Planning cycle: a named, dated interval work flows through, which nests.
|
|
12340
|
+
planning_cycle: {
|
|
12341
|
+
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." },
|
|
12342
|
+
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.' },
|
|
12343
|
+
starts_on: { type: "string", description: "ISO date the interval opens. A cycle is concretely dated, unlike a coarse `time_horizon` label." },
|
|
12344
|
+
ends_on: { type: "string", description: "ISO date the interval closes." },
|
|
12345
|
+
sequence: { type: "number", description: "The cycle / iteration number (e.g. Sprint 47, PI 3)." },
|
|
12346
|
+
goal: { type: "string", description: "The interval's goal or focus: what this cadence box is for." },
|
|
12347
|
+
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").' }
|
|
12348
|
+
},
|
|
12270
12349
|
// PlaybookProperties: Customer success playbook.
|
|
12271
12350
|
playbook: {
|
|
12272
12351
|
playbook_type: { type: "string", enum: ["onboarding", "expansion", "renewal", "rescue", "other"], description: "Scenario this playbook addresses" },
|
|
@@ -12818,7 +12897,7 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
12818
12897
|
// StrategicThemeProperties: StrategicTheme entity.
|
|
12819
12898
|
strategic_theme: {
|
|
12820
12899
|
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"' },
|
|
12900
|
+
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
12901
|
description: { type: "string", description: "Short narrative of this time-bound thrust within its pillar" },
|
|
12823
12902
|
scope: { type: "string", description: "What the theme explicitly includes or excludes" }
|
|
12824
12903
|
},
|
|
@@ -12914,7 +12993,9 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
12914
12993
|
effort: { type: "string", description: 'Effort estimate (e.g. "2h", "1d", "3 points"). Use a consistent unit within your team.' },
|
|
12915
12994
|
priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Relative importance against other tasks" },
|
|
12916
12995
|
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." }
|
|
12996
|
+
labels: { type: "string[]", description: "Free-form classification tags. Applied uniformly across work item types." },
|
|
12997
|
+
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.' },
|
|
12998
|
+
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
12999
|
},
|
|
12919
13000
|
// TeamProperties: Team entity.
|
|
12920
13001
|
team: {
|
|
@@ -13129,7 +13210,13 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
13129
13210
|
as_a: { type: "string", description: '"As a [persona], \u2026". Free-text persona name or slug ref.' },
|
|
13130
13211
|
i_want_to: { type: "string", description: "Capability or action the persona wants." },
|
|
13131
13212
|
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." }
|
|
13213
|
+
text: { type: "string", description: "Free-form story text. Used as a single-line rendered view." },
|
|
13214
|
+
assignee: { type: "string", description: "Assigned person. Promote to a `node_owned_by_person` edge if ownership must be queryable." },
|
|
13215
|
+
effort: { type: "string", description: 'Effort estimate (e.g. "2h", "1d", "3 points"). Use a consistent unit within your team.' },
|
|
13216
|
+
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." },
|
|
13217
|
+
due_date: { type: "string", description: "ISO date due. Typically bounded by the release or planning_cycle the story is scheduled into." },
|
|
13218
|
+
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.' },
|
|
13219
|
+
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
13220
|
},
|
|
13134
13221
|
// ValueObjectProperties: DDD value object.
|
|
13135
13222
|
value_object: {
|
|
@@ -19775,6 +19862,7 @@ var ENTITY_EMOJI = {
|
|
|
19775
19862
|
persona: "\u{1F3AD}",
|
|
19776
19863
|
pipeline_sales: "\u{1FA88}",
|
|
19777
19864
|
pipeline_stage: "\u{1F9FD}",
|
|
19865
|
+
planning_cycle: "\u{1F5D3}\uFE0F",
|
|
19778
19866
|
playbook: "\u{1F4D2}",
|
|
19779
19867
|
portfolio: "\u{1F9F8}",
|
|
19780
19868
|
positioning: "\u{1F3AA}",
|
|
@@ -20466,6 +20554,7 @@ var STANDARD_LABELS = {
|
|
|
20466
20554
|
roadmap_item: { alt_labels: ["roadmap entry", "planned item"] },
|
|
20467
20555
|
roadmap_theme: { alt_labels: ["product theme", "roadmap theme"] },
|
|
20468
20556
|
// UPG-660: renamed from bare 'theme' (N6 lineage)
|
|
20557
|
+
planning_cycle: { alt_labels: ["sprint", "iteration", "cycle", "program increment", "pi", "cadence", "time-box", "cooldown", "quarter"] },
|
|
20469
20558
|
// Engineering layer
|
|
20470
20559
|
bounded_context: { alt_labels: ["context", "domain boundary", "module boundary"] },
|
|
20471
20560
|
service: { alt_labels: ["microservice", "backend service", "api service"] },
|
|
@@ -22987,13 +23076,19 @@ var PRODUCT_SPEC_GUIDE = {
|
|
|
22987
23076
|
// registered to product_spec but missing from the navigation order).
|
|
22988
23077
|
// `changelog` lives here because it is a structural product-shipping
|
|
22989
23078
|
// 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"],
|
|
23079
|
+
creation_sequence: ["feature_area", "feature", "epic", "user_story", "acceptance_criterion", "task", "bug", "release", "roadmap", "roadmap_item", "roadmap_theme", "changelog", "planning_cycle"],
|
|
22991
23080
|
patterns: [
|
|
22992
23081
|
{
|
|
22993
23082
|
name: "Feature Decomposition",
|
|
22994
23083
|
description: "Features group into areas, decompose into epics, epics specify user stories (the templated promise), and tasks implement them as the engineering work",
|
|
22995
23084
|
entity_types: ["feature_area", "feature", "epic", "user_story", "task"],
|
|
22996
23085
|
edge_chain: ["feature_area_contains_feature", "feature_decomposed_into_epic", "epic_specified_by_user_story", "task_implements_user_story"]
|
|
23086
|
+
},
|
|
23087
|
+
{
|
|
23088
|
+
name: "Planning Cadence",
|
|
23089
|
+
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.",
|
|
23090
|
+
entity_types: ["planning_cycle", "user_story", "objective"],
|
|
23091
|
+
edge_chain: ["planning_cycle_contains_planning_cycle", "planning_cycle_schedules_user_story", "objective_scoped_to_planning_cycle"]
|
|
22997
23092
|
}
|
|
22998
23093
|
],
|
|
22999
23094
|
required_bridges: [
|
|
@@ -26262,6 +26357,40 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26262
26357
|
severity: "high",
|
|
26263
26358
|
source: { kind: "practitioner", attribution: "John Cutler, Outcomes over Output" }
|
|
26264
26359
|
},
|
|
26360
|
+
{
|
|
26361
|
+
id: "planning-cycle-without-scheduled-work",
|
|
26362
|
+
name: "Planning cycle with no scheduled work",
|
|
26363
|
+
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.",
|
|
26364
|
+
structured_condition: {
|
|
26365
|
+
operator: "and",
|
|
26366
|
+
checks: [
|
|
26367
|
+
{ check: { type: "entity_count", entity_type: "planning_cycle", comparison: "nonzero" } },
|
|
26368
|
+
{
|
|
26369
|
+
check: {
|
|
26370
|
+
type: "relationship",
|
|
26371
|
+
source_type: "planning_cycle",
|
|
26372
|
+
edge_type: "planning_cycle_schedules_user_story",
|
|
26373
|
+
target_type: "user_story",
|
|
26374
|
+
comparison: "not_exists"
|
|
26375
|
+
}
|
|
26376
|
+
},
|
|
26377
|
+
{
|
|
26378
|
+
check: {
|
|
26379
|
+
type: "relationship",
|
|
26380
|
+
source_type: "planning_cycle",
|
|
26381
|
+
edge_type: "planning_cycle_contains_planning_cycle",
|
|
26382
|
+
target_type: "planning_cycle",
|
|
26383
|
+
comparison: "not_exists"
|
|
26384
|
+
}
|
|
26385
|
+
}
|
|
26386
|
+
]
|
|
26387
|
+
},
|
|
26388
|
+
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.",
|
|
26389
|
+
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.",
|
|
26390
|
+
stages: ["build", "beta", "launch", "growth", "mature"],
|
|
26391
|
+
severity: "low",
|
|
26392
|
+
since: "0.20.0"
|
|
26393
|
+
},
|
|
26265
26394
|
// ── Market intelligence layer ───────────────────────────────────────────
|
|
26266
26395
|
{
|
|
26267
26396
|
id: "competitors-missing-past-validation",
|
|
@@ -27090,6 +27219,16 @@ var UPG_REGIONS = [
|
|
|
27090
27219
|
edge_id: "outcome_delivered_via_feature_area",
|
|
27091
27220
|
crosses_into: "product_delivery"
|
|
27092
27221
|
},
|
|
27222
|
+
{
|
|
27223
|
+
direction: "export",
|
|
27224
|
+
edge_id: "objective_scoped_to_planning_cycle",
|
|
27225
|
+
crosses_into: "product_delivery"
|
|
27226
|
+
},
|
|
27227
|
+
{
|
|
27228
|
+
direction: "export",
|
|
27229
|
+
edge_id: "strategic_theme_scoped_to_planning_cycle",
|
|
27230
|
+
crosses_into: "product_delivery"
|
|
27231
|
+
},
|
|
27093
27232
|
{
|
|
27094
27233
|
direction: "import",
|
|
27095
27234
|
edge_id: "feature_drives_key_result",
|
|
@@ -27901,6 +28040,11 @@ var UPG_REGIONS = [
|
|
|
27901
28040
|
{
|
|
27902
28041
|
type: "status_report",
|
|
27903
28042
|
role: "leaf"
|
|
28043
|
+
},
|
|
28044
|
+
{
|
|
28045
|
+
type: "planning_cycle",
|
|
28046
|
+
role: "container",
|
|
28047
|
+
notes: "self-nesting cadence axis"
|
|
27904
28048
|
}
|
|
27905
28049
|
],
|
|
27906
28050
|
anchor: {
|
|
@@ -27924,7 +28068,9 @@ var UPG_REGIONS = [
|
|
|
27924
28068
|
"roadmap_theme_spans_feature_area",
|
|
27925
28069
|
"milestone_gates_release",
|
|
27926
28070
|
"roadmap_item_references_feature",
|
|
27927
|
-
"feature_request_voted_on_by_feedback_vote"
|
|
28071
|
+
"feature_request_voted_on_by_feedback_vote",
|
|
28072
|
+
"planning_cycle_contains_planning_cycle",
|
|
28073
|
+
"planning_cycle_schedules_user_story"
|
|
27928
28074
|
],
|
|
27929
28075
|
boundary_edges: [
|
|
27930
28076
|
{
|
|
@@ -27932,6 +28078,16 @@ var UPG_REGIONS = [
|
|
|
27932
28078
|
edge_id: "outcome_delivered_by_feature",
|
|
27933
28079
|
crosses_into: "strategy_outcomes"
|
|
27934
28080
|
},
|
|
28081
|
+
{
|
|
28082
|
+
direction: "import",
|
|
28083
|
+
edge_id: "objective_scoped_to_planning_cycle",
|
|
28084
|
+
crosses_into: "strategy_outcomes"
|
|
28085
|
+
},
|
|
28086
|
+
{
|
|
28087
|
+
direction: "import",
|
|
28088
|
+
edge_id: "strategic_theme_scoped_to_planning_cycle",
|
|
28089
|
+
crosses_into: "strategy_outcomes"
|
|
28090
|
+
},
|
|
27935
28091
|
{
|
|
27936
28092
|
direction: "import",
|
|
27937
28093
|
edge_id: "outcome_delivered_via_feature_area",
|
|
@@ -29744,7 +29900,7 @@ function isCanonical(text) {
|
|
|
29744
29900
|
}
|
|
29745
29901
|
|
|
29746
29902
|
// src/index.ts
|
|
29747
|
-
var UPG_VERSION = "0.
|
|
29903
|
+
var UPG_VERSION = "0.20.0";
|
|
29748
29904
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
29749
29905
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
29750
29906
|
var UPG_TYPES = getTypes();
|