@unified-product-graph/core 0.6.1 → 0.7.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 +32 -0
- package/dist/index.cjs +99 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -16
- package/dist/index.d.ts +16 -16
- package/dist/index.js +99 -94
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,38 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## [0.7.0] — 2026-05-28
|
|
15
|
+
|
|
16
|
+
**Minor.** Re-canonicalise the user story (UPG-571). `story_statement` → `user_story`.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **`story_statement` → `user_story`.** The v0.2.7 Statement/Implementation split was sound — it extracted the lifecycle-bearing work into `task` — but renamed the surviving statement half to the coined `story_statement`. "User story" is the universally-recognised industry term for the templated "As X, I want Y so Z" promise, and UPG's value is being the recognisable canonical vocabulary — so the statement is re-canonicalised under `user_story`. The split itself is unchanged: the canonical shape remains a lifecycle-free `user_story` (statement) + a `task` (work), linked by `task_implements_user_story`.
|
|
21
|
+
- `user_story` (`ent_073`) is canonical again (`proposed`, lifecycle-free); `story_statement` (`ent_342`) is now deprecated (`replacement: user_story`).
|
|
22
|
+
- Four edges renamed: `epic_specified_by_story_statement` → `epic_specified_by_user_story`; `story_statement_verified_by_acceptance_criterion` → `user_story_verified_by_acceptance_criterion`; `task_implements_story_statement` → `task_implements_user_story`; `test_case_covers_story_statement` → `test_case_covers_user_story`.
|
|
23
|
+
|
|
24
|
+
### Migration
|
|
25
|
+
|
|
26
|
+
- `UPG_MIGRATIONS['0.7.0']`: `story_statement` → `user_story` (1→1 type rename; identical property surface `as_a` / `i_want_to` / `so_that` / `text` — no property migration).
|
|
27
|
+
- `UPG_EDGE_MIGRATIONS['0.7.0']`: the four edge renames above (endpoint guards target the post-migration `user_story` type).
|
|
28
|
+
- The v0.2.7 `user_story` → statement + task split is retained as the historical record. Legacy graphs migrate `user_story` (bundle) → `story_statement` + `task` at 0.2.7, then `story_statement` → `user_story` at 0.7.0 — converging on the canonical `user_story` (statement) + `task`.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## [0.6.2] — 2026-05-27
|
|
33
|
+
|
|
34
|
+
**Patch.** Sync `FrameworkCategory` with the framework library.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- `FrameworkCategory` was missing 6 values (`security`, `qa_testing`, `legal_compliance`, `content`, `education`, `localisation`) that framework definitions already referenced — which broke the TypeScript build in downstream consumers (e.g. the docs site's `FrameworksView`). Purely additive; no existing value changed.
|
|
39
|
+
|
|
40
|
+
## [0.6.1] — 2026-05-26
|
|
41
|
+
|
|
42
|
+
**Patch.** Metadata only: `UPG_VERSION` spec constant aligned to 0.6.x and `repository` repointed to the public `unified-product-graph/spec` mirror. No API or schema changes.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
14
46
|
## [0.6.0] — 2026-05-22
|
|
15
47
|
|
|
16
48
|
**Minor.** v1 editorial cut: the public framework surface is narrowed to the 34 canonical, famous frameworks (Wardley Map, BMC, OST, RICE, JTBD, North Star, OKR, AARRR, Porter Five Forces, RACI, C4, etc.) — one entry per famous-author archetype, balanced across the six lifecycle bands. The broader research catalog of 182 additional definitions is retained internally for tier-1 wiring tests and future promotion but is no longer re-exported from the package entry point or shipped in mirrors. Also lands the status-migrations axis prepared during the unreleased window.
|
package/dist/index.cjs
CHANGED
|
@@ -287,7 +287,7 @@ var UPG_DOMAINS = [
|
|
|
287
287
|
"feature",
|
|
288
288
|
"feature_area",
|
|
289
289
|
"epic",
|
|
290
|
-
"
|
|
290
|
+
"user_story",
|
|
291
291
|
"acceptance_criterion",
|
|
292
292
|
"release",
|
|
293
293
|
"task",
|
|
@@ -809,20 +809,19 @@ var UPG_ENTITY_META = [
|
|
|
809
809
|
{ name: "feature_area", type_id: "ent_314", maturity: "stable", since: "0.1.0" },
|
|
810
810
|
{ name: "feature", type_id: "ent_071", maturity: "stable", since: "0.1.0" },
|
|
811
811
|
{ name: "epic", type_id: "ent_072", maturity: "stable", since: "0.1.0" },
|
|
812
|
-
//
|
|
813
|
-
//
|
|
814
|
-
// `
|
|
815
|
-
//
|
|
816
|
-
//
|
|
817
|
-
//
|
|
818
|
-
//
|
|
819
|
-
//
|
|
820
|
-
//
|
|
821
|
-
//
|
|
822
|
-
//
|
|
823
|
-
|
|
824
|
-
{ name: "
|
|
825
|
-
{ name: "story_statement", type_id: "ent_342", maturity: "proposed", since: "0.2.7" },
|
|
812
|
+
// `user_story` is the templated "As X, I want Y so Z" promise — a stable,
|
|
813
|
+
// lifecycle-free design artefact (UCS pattern P5). The v0.2.7 split EXTRACTED
|
|
814
|
+
// the engineering work into a separate `task` (the lifecycle-bearing work-unit,
|
|
815
|
+
// linked via `task_implements_user_story`); the split was right. But the
|
|
816
|
+
// surviving statement half was renamed to the coined `story_statement`, which
|
|
817
|
+
// raised the adoption barrier — "user story" is the universally-recognised
|
|
818
|
+
// industry term for exactly this artefact. v0.7.0 (UPG-571) re-canonicalises
|
|
819
|
+
// the statement under `user_story`; `story_statement` becomes a deprecated
|
|
820
|
+
// alias. `story_task` (the original work half) was already collapsed into
|
|
821
|
+
// canonical `task` at v0.4.0. So the canonical shape is: user_story (statement)
|
|
822
|
+
// + task (work), linked by `task_implements_user_story`.
|
|
823
|
+
{ name: "user_story", type_id: "ent_073", maturity: "proposed", since: "0.1.0" },
|
|
824
|
+
{ name: "story_statement", type_id: "ent_342", maturity: "deprecated", since: "0.2.7", deprecated_in: "0.7.0", replacement: "user_story" },
|
|
826
825
|
{ name: "story_task", type_id: "ent_343", maturity: "deprecated", since: "0.2.7", deprecated_in: "0.4.0", replacement: "task" },
|
|
827
826
|
{ name: "acceptance_criterion", type_id: "ent_074", maturity: "stable", since: "0.1.0" },
|
|
828
827
|
{ name: "release", type_id: "ent_075", maturity: "stable", since: "0.1.0" },
|
|
@@ -1406,16 +1405,15 @@ var UPG_EDGE_CATALOG = {
|
|
|
1406
1405
|
outcome_delivered_by_feature: { forward_verb: "delivered_by", reverse_verb: "delivers", classification: "cross-domain", source_type: "outcome", target_type: "feature" },
|
|
1407
1406
|
outcome_delivered_via_feature_area: { forward_verb: "delivered_via", reverse_verb: "delivers_for", classification: "cross-domain", source_type: "outcome", target_type: "feature_area" },
|
|
1408
1407
|
feature_decomposed_into_epic: { forward_verb: "decomposed_into", reverse_verb: "implements", classification: "hierarchy", source_type: "feature", target_type: "epic" },
|
|
1409
|
-
// user_story
|
|
1410
|
-
//
|
|
1411
|
-
//
|
|
1412
|
-
//
|
|
1413
|
-
//
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
task_implements_story_statement: { forward_verb: "implements", reverse_verb: "implemented_by", classification: "cross-domain", source_type: "task", target_type: "story_statement" },
|
|
1408
|
+
// user_story (P5 templated-statement, the "As X, I want Y so Z" lifecycle-free
|
|
1409
|
+
// promise) verifies through acceptance criteria, is covered by test cases, and
|
|
1410
|
+
// is specified by epics; the paired `task` carries the lifecycle and the
|
|
1411
|
+
// implementation work, and implements the statement. (v0.2.7 split extracted
|
|
1412
|
+
// the work into `task`; v0.7.0/UPG-571 re-canonicalised the statement
|
|
1413
|
+
// story_statement → user_story — see UPG_EDGE_MIGRATIONS['0.7.0'].)
|
|
1414
|
+
epic_specified_by_user_story: { forward_verb: "specified_by", reverse_verb: "specifies", classification: "hierarchy", source_type: "epic", target_type: "user_story" },
|
|
1415
|
+
user_story_verified_by_acceptance_criterion: { forward_verb: "verified_by", reverse_verb: "verifies", classification: "hierarchy", source_type: "user_story", target_type: "acceptance_criterion" },
|
|
1416
|
+
task_implements_user_story: { forward_verb: "implements", reverse_verb: "implemented_by", classification: "cross-domain", source_type: "task", target_type: "user_story" },
|
|
1419
1417
|
feature_affected_by_bug: { forward_verb: "affected_by", reverse_verb: "affects", classification: "hierarchy", source_type: "feature", target_type: "bug" },
|
|
1420
1418
|
// release containment edges — used by the GitHub adapter when
|
|
1421
1419
|
// importing milestone→issue relationships. resolveContainmentEdge('release',
|
|
@@ -1431,10 +1429,10 @@ var UPG_EDGE_CATALOG = {
|
|
|
1431
1429
|
// feature_area is not contained by theme — themes span multiple
|
|
1432
1430
|
// areas cross-cuttingly. Containment path: product → feature_area.
|
|
1433
1431
|
theme_spans_feature_area: { forward_verb: "spans", reverse_verb: "spanned_by", classification: "semantic", source_type: "theme", target_type: "feature_area" },
|
|
1434
|
-
// `
|
|
1435
|
-
// canonical `
|
|
1436
|
-
//
|
|
1437
|
-
//
|
|
1432
|
+
// The legacy `story_task` collapsed into `task` (v0.4.0), so the implements
|
|
1433
|
+
// relationship is the canonical `task_implements_user_story` above — there is
|
|
1434
|
+
// no separate story_task edge. (v0.2.7 introduced the Statement/Implementation
|
|
1435
|
+
// split; v0.7.0/UPG-571 re-canonicalised the statement to user_story.)
|
|
1438
1436
|
bug_affects_feature: { forward_verb: "affects", reverse_verb: "affected_by", classification: "cross-domain", source_type: "bug", target_type: "feature" },
|
|
1439
1437
|
roadmap_item_references_feature: { forward_verb: "references", reverse_verb: "referenced_by", classification: "cross-domain", source_type: "roadmap_item", target_type: "feature" },
|
|
1440
1438
|
feature_decomposes_into_task: { forward_verb: "decomposes_into", reverse_verb: "implements", classification: "hierarchy", source_type: "feature", target_type: "task" },
|
|
@@ -1684,7 +1682,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
1684
1682
|
test_suite_covers_feature: { forward_verb: "covers", reverse_verb: "covered_by", classification: "cross-domain", source_type: "test_suite", target_type: "feature" },
|
|
1685
1683
|
test_environment_mirrors_deployment: { forward_verb: "mirrors", reverse_verb: "mirrored_by", classification: "cross-domain", source_type: "test_environment", target_type: "deployment" },
|
|
1686
1684
|
regression_test_guards_release: { forward_verb: "guards", reverse_verb: "guarded_by", classification: "cross-domain", source_type: "regression_test", target_type: "release" },
|
|
1687
|
-
|
|
1685
|
+
test_case_covers_user_story: { forward_verb: "covers", reverse_verb: "covered_by", classification: "cross-domain", source_type: "test_case", target_type: "user_story" },
|
|
1688
1686
|
qa_session_targets_feature: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "cross-domain", source_type: "qa_session", target_type: "feature" },
|
|
1689
1687
|
test_coverage_report_covers_service: { forward_verb: "covers", reverse_verb: "covered_by", classification: "cross-domain", source_type: "test_coverage_report", target_type: "service" },
|
|
1690
1688
|
test_suite_produces_test_result: { forward_verb: "produces", reverse_verb: "produced_by", classification: "causal", source_type: "test_suite", target_type: "test_result" },
|
|
@@ -3229,12 +3227,12 @@ var UPG_VALID_CHILDREN = {
|
|
|
3229
3227
|
],
|
|
3230
3228
|
// ── Product Specification hierarchy ─────────────────────────────────────────
|
|
3231
3229
|
// story_task collapsed into canonical task. feature now owns
|
|
3232
|
-
// task directly; story-derived tasks implement
|
|
3233
|
-
//
|
|
3230
|
+
// task directly; story-derived tasks implement user_story via
|
|
3231
|
+
// task_implements_user_story edge.
|
|
3234
3232
|
feature: ["epic", "bug", "task"],
|
|
3235
3233
|
feature_area: ["feature", "feature_area"],
|
|
3236
|
-
epic: ["
|
|
3237
|
-
|
|
3234
|
+
epic: ["user_story"],
|
|
3235
|
+
user_story: ["acceptance_criterion"],
|
|
3238
3236
|
task: ["task"],
|
|
3239
3237
|
// ── Engineering hierarchy ───────────────────────────────────────────────────
|
|
3240
3238
|
bounded_context: [
|
|
@@ -4363,37 +4361,6 @@ var EPIC_LIFECYCLE = {
|
|
|
4363
4361
|
}
|
|
4364
4362
|
]
|
|
4365
4363
|
};
|
|
4366
|
-
var USER_STORY_LIFECYCLE = {
|
|
4367
|
-
entity_type: "user_story",
|
|
4368
|
-
initial_phase: "draft",
|
|
4369
|
-
terminal_phases: ["done"],
|
|
4370
|
-
phases: [
|
|
4371
|
-
{
|
|
4372
|
-
id: "draft",
|
|
4373
|
-
label: "Draft",
|
|
4374
|
-
description: "The story has been written but has not been reviewed or refined. It may not yet have acceptance criteria.",
|
|
4375
|
-
transitions_to: ["ready"]
|
|
4376
|
-
},
|
|
4377
|
-
{
|
|
4378
|
-
id: "ready",
|
|
4379
|
-
label: "Ready",
|
|
4380
|
-
description: "The story has been refined. Acceptance criteria are defined. It is ready to be pulled into a sprint.",
|
|
4381
|
-
transitions_to: ["in_progress"]
|
|
4382
|
-
},
|
|
4383
|
-
{
|
|
4384
|
-
id: "in_progress",
|
|
4385
|
-
label: "In Progress",
|
|
4386
|
-
description: "A developer is actively working on this story.",
|
|
4387
|
-
transitions_to: ["done"]
|
|
4388
|
-
},
|
|
4389
|
-
{
|
|
4390
|
-
id: "done",
|
|
4391
|
-
label: "Done",
|
|
4392
|
-
description: "The story meets all acceptance criteria and has been merged and verified.",
|
|
4393
|
-
transitions_to: []
|
|
4394
|
-
}
|
|
4395
|
-
]
|
|
4396
|
-
};
|
|
4397
4364
|
var RELEASE_LIFECYCLE = {
|
|
4398
4365
|
entity_type: "release",
|
|
4399
4366
|
initial_phase: "planned",
|
|
@@ -5894,9 +5861,9 @@ var UPG_LIFECYCLES = [
|
|
|
5894
5861
|
FEATURE_AREA_LIFECYCLE,
|
|
5895
5862
|
FEATURE_LIFECYCLE,
|
|
5896
5863
|
EPIC_LIFECYCLE,
|
|
5897
|
-
|
|
5898
|
-
// story_task lifecycle removed v0.4.0 collapsed
|
|
5899
|
-
//
|
|
5864
|
+
// user_story is lifecycle-free (declared in UPG_LIFECYCLE_FREE_TYPES below).
|
|
5865
|
+
// story_task lifecycle removed v0.4.0 — collapsed into task (TASK_LIFECYCLE,
|
|
5866
|
+
// WORK_ITEM_TEMPLATE).
|
|
5900
5867
|
RELEASE_LIFECYCLE,
|
|
5901
5868
|
TASK_LIFECYCLE,
|
|
5902
5869
|
BUG_LIFECYCLE,
|
|
@@ -6003,12 +5970,13 @@ var UPG_LIFECYCLE_FREE_TYPES = /* @__PURE__ */ new Set([
|
|
|
6003
5970
|
"brand_typography",
|
|
6004
5971
|
"brand_imagery",
|
|
6005
5972
|
// ── Product Specification (4 of 5) — criteria, grouping, historical, +
|
|
6006
|
-
//
|
|
6007
|
-
//
|
|
5973
|
+
// user_story (the templated promise is a stable design artefact; the paired
|
|
5974
|
+
// task carries the lifecycle). Re-canon story_statement → user_story at
|
|
5975
|
+
// v0.7.0/UPG-571. ─
|
|
6008
5976
|
"acceptance_criterion",
|
|
6009
5977
|
"changelog",
|
|
6010
5978
|
"theme",
|
|
6011
|
-
"
|
|
5979
|
+
"user_story",
|
|
6012
5980
|
// ── Strategy — metric is a measurement definition; metric_quality_assessment
|
|
6013
5981
|
// is a point-in-time snapshot; value_stream is a mapped flow;
|
|
6014
5982
|
// constraint carries its own `constraint_status` enum (binding/advisory/
|
|
@@ -6494,6 +6462,23 @@ function getEnumValueMeta(scaleName, value) {
|
|
|
6494
6462
|
|
|
6495
6463
|
// src/grammar/migrations.ts
|
|
6496
6464
|
var UPG_MIGRATIONS = {
|
|
6465
|
+
"0.7.0": [
|
|
6466
|
+
// (since v0.7.0, UPG-571) story_statement → user_story. The v0.2.7 split
|
|
6467
|
+
// correctly separated the templated promise from the engineering work
|
|
6468
|
+
// (task), but renamed the surviving statement half to the coined
|
|
6469
|
+
// `story_statement`. "User story" is the universally-recognised industry
|
|
6470
|
+
// term for exactly that artefact, and UPG's value is being the recognisable
|
|
6471
|
+
// canonical vocabulary — so the statement is re-canonicalised under
|
|
6472
|
+
// `user_story`. Lifecycle-free, same property surface (as_a / i_want_to /
|
|
6473
|
+
// so_that / text); no property migration required. The paired `task` and
|
|
6474
|
+
// the `task_implements_*` / `epic_specified_by_*` / `*_verified_by_*` /
|
|
6475
|
+
// `test_case_covers_*` edges are renamed in UPG_EDGE_MIGRATIONS['0.7.0'].
|
|
6476
|
+
{
|
|
6477
|
+
from: "story_statement",
|
|
6478
|
+
to: "user_story",
|
|
6479
|
+
reason: 'story_statement re-canonicalised to user_story (UPG-571). The v0.2.7 Statement/Implementation split was sound \u2014 it extracted the lifecycle-bearing work into `task` \u2014 but the coined `story_statement` name raised the adoption barrier; "user story" is the industry-standard term for the templated promise. Lifecycle-free, identical property surface (as_a / i_want_to / so_that / text); no property migration needed.'
|
|
6480
|
+
}
|
|
6481
|
+
],
|
|
6497
6482
|
"0.4.0": [
|
|
6498
6483
|
// (since v0.4.0) hypothesis_claim reverts to hypothesis (the simpler
|
|
6499
6484
|
// canonical name — "claim" is implied). hypothesis_evidence deprecated
|
|
@@ -7484,6 +7469,18 @@ function getSplitMigrations(fromVersion, toVersion) {
|
|
|
7484
7469
|
return result;
|
|
7485
7470
|
}
|
|
7486
7471
|
var UPG_EDGE_MIGRATIONS = {
|
|
7472
|
+
"0.7.0": [
|
|
7473
|
+
// (since v0.7.0, UPG-571) story_statement → user_story re-canon. The four
|
|
7474
|
+
// canonical edges that touch the statement are renamed to the user_story
|
|
7475
|
+
// form. Endpoint guards reference the POST-migration (user_story) types —
|
|
7476
|
+
// edge migration runs after node migration, so by the time these rules
|
|
7477
|
+
// apply the statement node has already been renamed story_statement →
|
|
7478
|
+
// user_story (UPG_MIGRATIONS['0.7.0']).
|
|
7479
|
+
{ kind: "rename", from: "task_implements_story_statement", to: "task_implements_user_story", requires_source_type: "task", requires_target_type: "user_story", reason: "story_statement \u2192 user_story (UPG-571). Task still implements the statement; edge key updated to the re-canonicalised target type." },
|
|
7480
|
+
{ kind: "rename", from: "epic_specified_by_story_statement", to: "epic_specified_by_user_story", requires_source_type: "epic", requires_target_type: "user_story", reason: "story_statement \u2192 user_story (UPG-571). Epics specify the statement; edge key updated to the re-canonicalised target type." },
|
|
7481
|
+
{ kind: "rename", from: "story_statement_verified_by_acceptance_criterion", to: "user_story_verified_by_acceptance_criterion", requires_source_type: "user_story", requires_target_type: "acceptance_criterion", reason: "story_statement \u2192 user_story (UPG-571). Acceptance criteria verify the statement; edge key updated to the re-canonicalised source type." },
|
|
7482
|
+
{ kind: "rename", from: "test_case_covers_story_statement", to: "test_case_covers_user_story", requires_source_type: "test_case", requires_target_type: "user_story", reason: "story_statement \u2192 user_story (UPG-571). Test cases cover the statement; edge key updated to the re-canonicalised target type." }
|
|
7483
|
+
],
|
|
7487
7484
|
"0.4.0": [
|
|
7488
7485
|
// ── hypothesis_claim → hypothesis reverse rename ───────────────
|
|
7489
7486
|
// Every edge that was renamed FROM hypothesis_* TO hypothesis_claim_* in
|
|
@@ -7964,18 +7961,19 @@ var UPG_EDGE_MIGRATIONS = {
|
|
|
7964
7961
|
requires_target_type: "story_statement",
|
|
7965
7962
|
reason: "Test cases cover the spec, not the work; retargets target to story_statement."
|
|
7966
7963
|
},
|
|
7967
|
-
//
|
|
7968
|
-
// story_task_implements_story_statement edge).
|
|
7964
|
+
// user_story_broken_into_task drops — consolidated into the implements edge.
|
|
7969
7965
|
{
|
|
7970
7966
|
kind: "drop",
|
|
7971
7967
|
from: "user_story_broken_into_task",
|
|
7972
|
-
reason: 'Consolidated into the canonical
|
|
7973
|
-
},
|
|
7974
|
-
{
|
|
7975
|
-
kind: "drop",
|
|
7976
|
-
from: "task_implements_user_story",
|
|
7977
|
-
reason: 'Consolidated as above \u2014 story_task IS the task, statements carry the implements relationship directly. CHANGELOG v0.2.7: "task_implements_user_story \u2192 dropped; consolidated as above."'
|
|
7968
|
+
reason: 'Consolidated into the canonical implements edge (the relationship now flows from task to statement directly). CHANGELOG v0.2.7: "user_story_broken_into_task \u2192 dropped."'
|
|
7978
7969
|
}
|
|
7970
|
+
// NOTE: the v0.2.7 drop of `task_implements_user_story` was REMOVED at v0.7.0
|
|
7971
|
+
// (UPG-571). Re-canonicalising story_statement → user_story makes
|
|
7972
|
+
// `task_implements_user_story` the canonical implements edge again, so the
|
|
7973
|
+
// name is no longer retired (a drop rule must never name a canonical edge).
|
|
7974
|
+
// Legacy pre-0.2.7 instances are reconnected by the v0.2.7 split's emitted
|
|
7975
|
+
// implements edge; any residual dangling edge is handled by
|
|
7976
|
+
// repair_dangling_edges.
|
|
7979
7977
|
],
|
|
7980
7978
|
"0.2.8": [
|
|
7981
7979
|
// ── split 3: 12 hypothesis-edge retargets + 1 drop ─────────────
|
|
@@ -11143,8 +11141,8 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
11143
11141
|
risks_flagged: { type: "number", description: "Number of risks flagged in this report" },
|
|
11144
11142
|
blockers: { type: "string", description: "Description of current blockers" }
|
|
11145
11143
|
},
|
|
11146
|
-
//
|
|
11147
|
-
|
|
11144
|
+
// UserStoryProperties — "As X, I want Y so Z" templated promise — a user story (UCS pattern P5).
|
|
11145
|
+
user_story: {
|
|
11148
11146
|
as_a: { type: "string", description: '"As a [persona], \u2026". Free-text persona name or slug ref.' },
|
|
11149
11147
|
i_want_to: { type: "string", description: "Capability or action the persona wants." },
|
|
11150
11148
|
so_that: { type: "string", description: "Benefit or outcome the persona expects." },
|
|
@@ -11706,7 +11704,7 @@ var UPG_FRAMEWORKS = [
|
|
|
11706
11704
|
},
|
|
11707
11705
|
{
|
|
11708
11706
|
"label": "User Stories",
|
|
11709
|
-
"entityTypeId": "
|
|
11707
|
+
"entityTypeId": "user_story",
|
|
11710
11708
|
"description": "Detailed stories prioritised vertically"
|
|
11711
11709
|
},
|
|
11712
11710
|
{
|
|
@@ -11726,7 +11724,7 @@ var UPG_FRAMEWORKS = [
|
|
|
11726
11724
|
"role": "bucket"
|
|
11727
11725
|
},
|
|
11728
11726
|
{
|
|
11729
|
-
"type": "
|
|
11727
|
+
"type": "user_story",
|
|
11730
11728
|
"role": "bucket"
|
|
11731
11729
|
},
|
|
11732
11730
|
{
|
|
@@ -16467,7 +16465,7 @@ var PRODUCT_DELIVERY_PLAYBOOK = {
|
|
|
16467
16465
|
seqStep(
|
|
16468
16466
|
3,
|
|
16469
16467
|
"Stories",
|
|
16470
|
-
["
|
|
16468
|
+
["user_story", "acceptance_criterion"],
|
|
16471
16469
|
'Write each feature from the user perspective. "As [persona], I want [job], so that [outcome]." Define acceptance criteria.'
|
|
16472
16470
|
),
|
|
16473
16471
|
seqStep(
|
|
@@ -17908,19 +17906,19 @@ var PRODUCT_SPEC_GUIDE = {
|
|
|
17908
17906
|
// registered to product_spec but missing from the navigation order).
|
|
17909
17907
|
// `changelog` lives here because it is a structural product-shipping
|
|
17910
17908
|
// artefact; content domain references it only via cross-domain bridges.
|
|
17911
|
-
creation_sequence: ["feature_area", "feature", "epic", "
|
|
17909
|
+
creation_sequence: ["feature_area", "feature", "epic", "user_story", "acceptance_criterion", "task", "bug", "release", "roadmap", "roadmap_item", "theme", "changelog"],
|
|
17912
17910
|
patterns: [
|
|
17913
17911
|
{
|
|
17914
17912
|
name: "Feature Decomposition",
|
|
17915
|
-
description: "Features group into areas, decompose into epics, epics specify
|
|
17916
|
-
entity_types: ["feature_area", "feature", "epic", "
|
|
17917
|
-
edge_chain: ["feature_area_contains_feature", "feature_decomposed_into_epic", "
|
|
17913
|
+
description: "Features group into areas, decompose into epics, epics specify user stories (the templated promise), and tasks implement them as the engineering work",
|
|
17914
|
+
entity_types: ["feature_area", "feature", "epic", "user_story", "task"],
|
|
17915
|
+
edge_chain: ["feature_area_contains_feature", "feature_decomposed_into_epic", "epic_specified_by_user_story", "task_implements_user_story"]
|
|
17918
17916
|
}
|
|
17919
17917
|
],
|
|
17920
17918
|
required_bridges: [
|
|
17921
17919
|
{ edge_type: "feature_tests_hypothesis", target_domain: "validation", when: "Features should trace back to validated hypotheses" },
|
|
17922
17920
|
{ edge_type: "outcome_delivered_by_feature", target_domain: "strategy", when: "Every feature should connect to a strategic outcome" },
|
|
17923
|
-
{ edge_type: "
|
|
17921
|
+
{ edge_type: "test_case_covers_user_story", target_domain: "testing", when: "User stories should have acceptance tests" }
|
|
17924
17922
|
],
|
|
17925
17923
|
anti_patterns: [
|
|
17926
17924
|
{ description: "Features without outcomes. Features serve strategic outcomes; the rest is waste." },
|
|
@@ -18101,7 +18099,7 @@ var TESTING_GUIDE = {
|
|
|
18101
18099
|
}
|
|
18102
18100
|
],
|
|
18103
18101
|
required_bridges: [
|
|
18104
|
-
{ edge_type: "
|
|
18102
|
+
{ edge_type: "test_case_covers_user_story", target_domain: "product_spec", when: "Test cases should trace back to user stories (which in turn trace to features via epics)" },
|
|
18105
18103
|
{ edge_type: "test_case_validates_acceptance_criterion", target_domain: "product_spec", when: 'Acceptance criteria define what "done" means and must be validated by tests' }
|
|
18106
18104
|
],
|
|
18107
18105
|
anti_patterns: [
|
|
@@ -19746,7 +19744,7 @@ var UPG_COUNT_BENCHMARKS = [
|
|
|
19746
19744
|
"rationale": "Epics group related stories. Not needed at idea stage."
|
|
19747
19745
|
},
|
|
19748
19746
|
{
|
|
19749
|
-
"type": "
|
|
19747
|
+
"type": "user_story",
|
|
19750
19748
|
"domain": "product_spec",
|
|
19751
19749
|
"concept": null,
|
|
19752
19750
|
"validation": {
|
|
@@ -20661,7 +20659,7 @@ var UPG_RATIO_BENCHMARKS = [
|
|
|
20661
20659
|
},
|
|
20662
20660
|
{
|
|
20663
20661
|
"name": "Story coverage",
|
|
20664
|
-
"numerator_type": "
|
|
20662
|
+
"numerator_type": "user_story",
|
|
20665
20663
|
"denominator_type": "feature",
|
|
20666
20664
|
"expected_min": 2,
|
|
20667
20665
|
"stages": [
|
|
@@ -22444,7 +22442,7 @@ var UPG_REGIONS = [
|
|
|
22444
22442
|
"feature_affected_by_bug",
|
|
22445
22443
|
"epic_specified_by_user_story",
|
|
22446
22444
|
"user_story_verified_by_acceptance_criterion",
|
|
22447
|
-
"
|
|
22445
|
+
"task_implements_user_story",
|
|
22448
22446
|
"roadmap_contains_roadmap_item",
|
|
22449
22447
|
"roadmap_categorised_by_theme",
|
|
22450
22448
|
"roadmap_schedules_release",
|
|
@@ -23314,6 +23312,8 @@ var UPG_FRAMEWORK_CATEGORIES = [
|
|
|
23314
23312
|
// Engineering & Ops
|
|
23315
23313
|
"engineering",
|
|
23316
23314
|
"devops",
|
|
23315
|
+
"security",
|
|
23316
|
+
"qa_testing",
|
|
23317
23317
|
"ai_ml",
|
|
23318
23318
|
"agentic",
|
|
23319
23319
|
// Growth & GTM
|
|
@@ -23322,12 +23322,17 @@ var UPG_FRAMEWORK_CATEGORIES = [
|
|
|
23322
23322
|
"go_to_market",
|
|
23323
23323
|
"sales",
|
|
23324
23324
|
"pricing",
|
|
23325
|
-
// Data & Ops
|
|
23325
|
+
// Data, Legal & Ops
|
|
23326
23326
|
"data_analytics",
|
|
23327
|
+
"legal_compliance",
|
|
23327
23328
|
"customer_success",
|
|
23328
23329
|
"team_process",
|
|
23329
23330
|
"program_mgmt",
|
|
23331
|
+
// Content & Portfolio
|
|
23332
|
+
"content",
|
|
23333
|
+
"education",
|
|
23330
23334
|
"partnerships",
|
|
23335
|
+
"localisation",
|
|
23331
23336
|
"portfolio"
|
|
23332
23337
|
];
|
|
23333
23338
|
var UPG_STRUCTURE_PATTERNS = [
|