@unified-product-graph/core 0.6.2 → 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 +18 -0
- package/dist/index.cjs +91 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -15
- package/dist/index.d.ts +15 -15
- package/dist/index.js +91 -93
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -96,7 +96,7 @@ var UPG_DOMAINS = [
|
|
|
96
96
|
"feature",
|
|
97
97
|
"feature_area",
|
|
98
98
|
"epic",
|
|
99
|
-
"
|
|
99
|
+
"user_story",
|
|
100
100
|
"acceptance_criterion",
|
|
101
101
|
"release",
|
|
102
102
|
"task",
|
|
@@ -618,20 +618,19 @@ var UPG_ENTITY_META = [
|
|
|
618
618
|
{ name: "feature_area", type_id: "ent_314", maturity: "stable", since: "0.1.0" },
|
|
619
619
|
{ name: "feature", type_id: "ent_071", maturity: "stable", since: "0.1.0" },
|
|
620
620
|
{ name: "epic", type_id: "ent_072", maturity: "stable", since: "0.1.0" },
|
|
621
|
-
//
|
|
622
|
-
//
|
|
623
|
-
// `
|
|
624
|
-
//
|
|
625
|
-
//
|
|
626
|
-
//
|
|
627
|
-
//
|
|
628
|
-
//
|
|
629
|
-
//
|
|
630
|
-
//
|
|
631
|
-
//
|
|
632
|
-
|
|
633
|
-
{ name: "
|
|
634
|
-
{ name: "story_statement", type_id: "ent_342", maturity: "proposed", since: "0.2.7" },
|
|
621
|
+
// `user_story` is the templated "As X, I want Y so Z" promise — a stable,
|
|
622
|
+
// lifecycle-free design artefact (UCS pattern P5). The v0.2.7 split EXTRACTED
|
|
623
|
+
// the engineering work into a separate `task` (the lifecycle-bearing work-unit,
|
|
624
|
+
// linked via `task_implements_user_story`); the split was right. But the
|
|
625
|
+
// surviving statement half was renamed to the coined `story_statement`, which
|
|
626
|
+
// raised the adoption barrier — "user story" is the universally-recognised
|
|
627
|
+
// industry term for exactly this artefact. v0.7.0 (UPG-571) re-canonicalises
|
|
628
|
+
// the statement under `user_story`; `story_statement` becomes a deprecated
|
|
629
|
+
// alias. `story_task` (the original work half) was already collapsed into
|
|
630
|
+
// canonical `task` at v0.4.0. So the canonical shape is: user_story (statement)
|
|
631
|
+
// + task (work), linked by `task_implements_user_story`.
|
|
632
|
+
{ name: "user_story", type_id: "ent_073", maturity: "proposed", since: "0.1.0" },
|
|
633
|
+
{ name: "story_statement", type_id: "ent_342", maturity: "deprecated", since: "0.2.7", deprecated_in: "0.7.0", replacement: "user_story" },
|
|
635
634
|
{ name: "story_task", type_id: "ent_343", maturity: "deprecated", since: "0.2.7", deprecated_in: "0.4.0", replacement: "task" },
|
|
636
635
|
{ name: "acceptance_criterion", type_id: "ent_074", maturity: "stable", since: "0.1.0" },
|
|
637
636
|
{ name: "release", type_id: "ent_075", maturity: "stable", since: "0.1.0" },
|
|
@@ -1215,16 +1214,15 @@ var UPG_EDGE_CATALOG = {
|
|
|
1215
1214
|
outcome_delivered_by_feature: { forward_verb: "delivered_by", reverse_verb: "delivers", classification: "cross-domain", source_type: "outcome", target_type: "feature" },
|
|
1216
1215
|
outcome_delivered_via_feature_area: { forward_verb: "delivered_via", reverse_verb: "delivers_for", classification: "cross-domain", source_type: "outcome", target_type: "feature_area" },
|
|
1217
1216
|
feature_decomposed_into_epic: { forward_verb: "decomposed_into", reverse_verb: "implements", classification: "hierarchy", source_type: "feature", target_type: "epic" },
|
|
1218
|
-
// user_story
|
|
1219
|
-
//
|
|
1220
|
-
//
|
|
1221
|
-
//
|
|
1222
|
-
//
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
task_implements_story_statement: { forward_verb: "implements", reverse_verb: "implemented_by", classification: "cross-domain", source_type: "task", target_type: "story_statement" },
|
|
1217
|
+
// user_story (P5 templated-statement, the "As X, I want Y so Z" lifecycle-free
|
|
1218
|
+
// promise) verifies through acceptance criteria, is covered by test cases, and
|
|
1219
|
+
// is specified by epics; the paired `task` carries the lifecycle and the
|
|
1220
|
+
// implementation work, and implements the statement. (v0.2.7 split extracted
|
|
1221
|
+
// the work into `task`; v0.7.0/UPG-571 re-canonicalised the statement
|
|
1222
|
+
// story_statement → user_story — see UPG_EDGE_MIGRATIONS['0.7.0'].)
|
|
1223
|
+
epic_specified_by_user_story: { forward_verb: "specified_by", reverse_verb: "specifies", classification: "hierarchy", source_type: "epic", target_type: "user_story" },
|
|
1224
|
+
user_story_verified_by_acceptance_criterion: { forward_verb: "verified_by", reverse_verb: "verifies", classification: "hierarchy", source_type: "user_story", target_type: "acceptance_criterion" },
|
|
1225
|
+
task_implements_user_story: { forward_verb: "implements", reverse_verb: "implemented_by", classification: "cross-domain", source_type: "task", target_type: "user_story" },
|
|
1228
1226
|
feature_affected_by_bug: { forward_verb: "affected_by", reverse_verb: "affects", classification: "hierarchy", source_type: "feature", target_type: "bug" },
|
|
1229
1227
|
// release containment edges — used by the GitHub adapter when
|
|
1230
1228
|
// importing milestone→issue relationships. resolveContainmentEdge('release',
|
|
@@ -1240,10 +1238,10 @@ var UPG_EDGE_CATALOG = {
|
|
|
1240
1238
|
// feature_area is not contained by theme — themes span multiple
|
|
1241
1239
|
// areas cross-cuttingly. Containment path: product → feature_area.
|
|
1242
1240
|
theme_spans_feature_area: { forward_verb: "spans", reverse_verb: "spanned_by", classification: "semantic", source_type: "theme", target_type: "feature_area" },
|
|
1243
|
-
// `
|
|
1244
|
-
// canonical `
|
|
1245
|
-
//
|
|
1246
|
-
//
|
|
1241
|
+
// The legacy `story_task` collapsed into `task` (v0.4.0), so the implements
|
|
1242
|
+
// relationship is the canonical `task_implements_user_story` above — there is
|
|
1243
|
+
// no separate story_task edge. (v0.2.7 introduced the Statement/Implementation
|
|
1244
|
+
// split; v0.7.0/UPG-571 re-canonicalised the statement to user_story.)
|
|
1247
1245
|
bug_affects_feature: { forward_verb: "affects", reverse_verb: "affected_by", classification: "cross-domain", source_type: "bug", target_type: "feature" },
|
|
1248
1246
|
roadmap_item_references_feature: { forward_verb: "references", reverse_verb: "referenced_by", classification: "cross-domain", source_type: "roadmap_item", target_type: "feature" },
|
|
1249
1247
|
feature_decomposes_into_task: { forward_verb: "decomposes_into", reverse_verb: "implements", classification: "hierarchy", source_type: "feature", target_type: "task" },
|
|
@@ -1493,7 +1491,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
1493
1491
|
test_suite_covers_feature: { forward_verb: "covers", reverse_verb: "covered_by", classification: "cross-domain", source_type: "test_suite", target_type: "feature" },
|
|
1494
1492
|
test_environment_mirrors_deployment: { forward_verb: "mirrors", reverse_verb: "mirrored_by", classification: "cross-domain", source_type: "test_environment", target_type: "deployment" },
|
|
1495
1493
|
regression_test_guards_release: { forward_verb: "guards", reverse_verb: "guarded_by", classification: "cross-domain", source_type: "regression_test", target_type: "release" },
|
|
1496
|
-
|
|
1494
|
+
test_case_covers_user_story: { forward_verb: "covers", reverse_verb: "covered_by", classification: "cross-domain", source_type: "test_case", target_type: "user_story" },
|
|
1497
1495
|
qa_session_targets_feature: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "cross-domain", source_type: "qa_session", target_type: "feature" },
|
|
1498
1496
|
test_coverage_report_covers_service: { forward_verb: "covers", reverse_verb: "covered_by", classification: "cross-domain", source_type: "test_coverage_report", target_type: "service" },
|
|
1499
1497
|
test_suite_produces_test_result: { forward_verb: "produces", reverse_verb: "produced_by", classification: "causal", source_type: "test_suite", target_type: "test_result" },
|
|
@@ -3038,12 +3036,12 @@ var UPG_VALID_CHILDREN = {
|
|
|
3038
3036
|
],
|
|
3039
3037
|
// ── Product Specification hierarchy ─────────────────────────────────────────
|
|
3040
3038
|
// story_task collapsed into canonical task. feature now owns
|
|
3041
|
-
// task directly; story-derived tasks implement
|
|
3042
|
-
//
|
|
3039
|
+
// task directly; story-derived tasks implement user_story via
|
|
3040
|
+
// task_implements_user_story edge.
|
|
3043
3041
|
feature: ["epic", "bug", "task"],
|
|
3044
3042
|
feature_area: ["feature", "feature_area"],
|
|
3045
|
-
epic: ["
|
|
3046
|
-
|
|
3043
|
+
epic: ["user_story"],
|
|
3044
|
+
user_story: ["acceptance_criterion"],
|
|
3047
3045
|
task: ["task"],
|
|
3048
3046
|
// ── Engineering hierarchy ───────────────────────────────────────────────────
|
|
3049
3047
|
bounded_context: [
|
|
@@ -4172,37 +4170,6 @@ var EPIC_LIFECYCLE = {
|
|
|
4172
4170
|
}
|
|
4173
4171
|
]
|
|
4174
4172
|
};
|
|
4175
|
-
var USER_STORY_LIFECYCLE = {
|
|
4176
|
-
entity_type: "user_story",
|
|
4177
|
-
initial_phase: "draft",
|
|
4178
|
-
terminal_phases: ["done"],
|
|
4179
|
-
phases: [
|
|
4180
|
-
{
|
|
4181
|
-
id: "draft",
|
|
4182
|
-
label: "Draft",
|
|
4183
|
-
description: "The story has been written but has not been reviewed or refined. It may not yet have acceptance criteria.",
|
|
4184
|
-
transitions_to: ["ready"]
|
|
4185
|
-
},
|
|
4186
|
-
{
|
|
4187
|
-
id: "ready",
|
|
4188
|
-
label: "Ready",
|
|
4189
|
-
description: "The story has been refined. Acceptance criteria are defined. It is ready to be pulled into a sprint.",
|
|
4190
|
-
transitions_to: ["in_progress"]
|
|
4191
|
-
},
|
|
4192
|
-
{
|
|
4193
|
-
id: "in_progress",
|
|
4194
|
-
label: "In Progress",
|
|
4195
|
-
description: "A developer is actively working on this story.",
|
|
4196
|
-
transitions_to: ["done"]
|
|
4197
|
-
},
|
|
4198
|
-
{
|
|
4199
|
-
id: "done",
|
|
4200
|
-
label: "Done",
|
|
4201
|
-
description: "The story meets all acceptance criteria and has been merged and verified.",
|
|
4202
|
-
transitions_to: []
|
|
4203
|
-
}
|
|
4204
|
-
]
|
|
4205
|
-
};
|
|
4206
4173
|
var RELEASE_LIFECYCLE = {
|
|
4207
4174
|
entity_type: "release",
|
|
4208
4175
|
initial_phase: "planned",
|
|
@@ -5703,9 +5670,9 @@ var UPG_LIFECYCLES = [
|
|
|
5703
5670
|
FEATURE_AREA_LIFECYCLE,
|
|
5704
5671
|
FEATURE_LIFECYCLE,
|
|
5705
5672
|
EPIC_LIFECYCLE,
|
|
5706
|
-
|
|
5707
|
-
// story_task lifecycle removed v0.4.0 collapsed
|
|
5708
|
-
//
|
|
5673
|
+
// user_story is lifecycle-free (declared in UPG_LIFECYCLE_FREE_TYPES below).
|
|
5674
|
+
// story_task lifecycle removed v0.4.0 — collapsed into task (TASK_LIFECYCLE,
|
|
5675
|
+
// WORK_ITEM_TEMPLATE).
|
|
5709
5676
|
RELEASE_LIFECYCLE,
|
|
5710
5677
|
TASK_LIFECYCLE,
|
|
5711
5678
|
BUG_LIFECYCLE,
|
|
@@ -5812,12 +5779,13 @@ var UPG_LIFECYCLE_FREE_TYPES = /* @__PURE__ */ new Set([
|
|
|
5812
5779
|
"brand_typography",
|
|
5813
5780
|
"brand_imagery",
|
|
5814
5781
|
// ── Product Specification (4 of 5) — criteria, grouping, historical, +
|
|
5815
|
-
//
|
|
5816
|
-
//
|
|
5782
|
+
// user_story (the templated promise is a stable design artefact; the paired
|
|
5783
|
+
// task carries the lifecycle). Re-canon story_statement → user_story at
|
|
5784
|
+
// v0.7.0/UPG-571. ─
|
|
5817
5785
|
"acceptance_criterion",
|
|
5818
5786
|
"changelog",
|
|
5819
5787
|
"theme",
|
|
5820
|
-
"
|
|
5788
|
+
"user_story",
|
|
5821
5789
|
// ── Strategy — metric is a measurement definition; metric_quality_assessment
|
|
5822
5790
|
// is a point-in-time snapshot; value_stream is a mapped flow;
|
|
5823
5791
|
// constraint carries its own `constraint_status` enum (binding/advisory/
|
|
@@ -6303,6 +6271,23 @@ function getEnumValueMeta(scaleName, value) {
|
|
|
6303
6271
|
|
|
6304
6272
|
// src/grammar/migrations.ts
|
|
6305
6273
|
var UPG_MIGRATIONS = {
|
|
6274
|
+
"0.7.0": [
|
|
6275
|
+
// (since v0.7.0, UPG-571) story_statement → user_story. The v0.2.7 split
|
|
6276
|
+
// correctly separated the templated promise from the engineering work
|
|
6277
|
+
// (task), but renamed the surviving statement half to the coined
|
|
6278
|
+
// `story_statement`. "User story" is the universally-recognised industry
|
|
6279
|
+
// term for exactly that artefact, and UPG's value is being the recognisable
|
|
6280
|
+
// canonical vocabulary — so the statement is re-canonicalised under
|
|
6281
|
+
// `user_story`. Lifecycle-free, same property surface (as_a / i_want_to /
|
|
6282
|
+
// so_that / text); no property migration required. The paired `task` and
|
|
6283
|
+
// the `task_implements_*` / `epic_specified_by_*` / `*_verified_by_*` /
|
|
6284
|
+
// `test_case_covers_*` edges are renamed in UPG_EDGE_MIGRATIONS['0.7.0'].
|
|
6285
|
+
{
|
|
6286
|
+
from: "story_statement",
|
|
6287
|
+
to: "user_story",
|
|
6288
|
+
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.'
|
|
6289
|
+
}
|
|
6290
|
+
],
|
|
6306
6291
|
"0.4.0": [
|
|
6307
6292
|
// (since v0.4.0) hypothesis_claim reverts to hypothesis (the simpler
|
|
6308
6293
|
// canonical name — "claim" is implied). hypothesis_evidence deprecated
|
|
@@ -7293,6 +7278,18 @@ function getSplitMigrations(fromVersion, toVersion) {
|
|
|
7293
7278
|
return result;
|
|
7294
7279
|
}
|
|
7295
7280
|
var UPG_EDGE_MIGRATIONS = {
|
|
7281
|
+
"0.7.0": [
|
|
7282
|
+
// (since v0.7.0, UPG-571) story_statement → user_story re-canon. The four
|
|
7283
|
+
// canonical edges that touch the statement are renamed to the user_story
|
|
7284
|
+
// form. Endpoint guards reference the POST-migration (user_story) types —
|
|
7285
|
+
// edge migration runs after node migration, so by the time these rules
|
|
7286
|
+
// apply the statement node has already been renamed story_statement →
|
|
7287
|
+
// user_story (UPG_MIGRATIONS['0.7.0']).
|
|
7288
|
+
{ 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." },
|
|
7289
|
+
{ 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." },
|
|
7290
|
+
{ 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." },
|
|
7291
|
+
{ 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." }
|
|
7292
|
+
],
|
|
7296
7293
|
"0.4.0": [
|
|
7297
7294
|
// ── hypothesis_claim → hypothesis reverse rename ───────────────
|
|
7298
7295
|
// Every edge that was renamed FROM hypothesis_* TO hypothesis_claim_* in
|
|
@@ -7773,18 +7770,19 @@ var UPG_EDGE_MIGRATIONS = {
|
|
|
7773
7770
|
requires_target_type: "story_statement",
|
|
7774
7771
|
reason: "Test cases cover the spec, not the work; retargets target to story_statement."
|
|
7775
7772
|
},
|
|
7776
|
-
//
|
|
7777
|
-
// story_task_implements_story_statement edge).
|
|
7773
|
+
// user_story_broken_into_task drops — consolidated into the implements edge.
|
|
7778
7774
|
{
|
|
7779
7775
|
kind: "drop",
|
|
7780
7776
|
from: "user_story_broken_into_task",
|
|
7781
|
-
reason: 'Consolidated into the canonical
|
|
7782
|
-
},
|
|
7783
|
-
{
|
|
7784
|
-
kind: "drop",
|
|
7785
|
-
from: "task_implements_user_story",
|
|
7786
|
-
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."'
|
|
7777
|
+
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."'
|
|
7787
7778
|
}
|
|
7779
|
+
// NOTE: the v0.2.7 drop of `task_implements_user_story` was REMOVED at v0.7.0
|
|
7780
|
+
// (UPG-571). Re-canonicalising story_statement → user_story makes
|
|
7781
|
+
// `task_implements_user_story` the canonical implements edge again, so the
|
|
7782
|
+
// name is no longer retired (a drop rule must never name a canonical edge).
|
|
7783
|
+
// Legacy pre-0.2.7 instances are reconnected by the v0.2.7 split's emitted
|
|
7784
|
+
// implements edge; any residual dangling edge is handled by
|
|
7785
|
+
// repair_dangling_edges.
|
|
7788
7786
|
],
|
|
7789
7787
|
"0.2.8": [
|
|
7790
7788
|
// ── split 3: 12 hypothesis-edge retargets + 1 drop ─────────────
|
|
@@ -10952,8 +10950,8 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
10952
10950
|
risks_flagged: { type: "number", description: "Number of risks flagged in this report" },
|
|
10953
10951
|
blockers: { type: "string", description: "Description of current blockers" }
|
|
10954
10952
|
},
|
|
10955
|
-
//
|
|
10956
|
-
|
|
10953
|
+
// UserStoryProperties — "As X, I want Y so Z" templated promise — a user story (UCS pattern P5).
|
|
10954
|
+
user_story: {
|
|
10957
10955
|
as_a: { type: "string", description: '"As a [persona], \u2026". Free-text persona name or slug ref.' },
|
|
10958
10956
|
i_want_to: { type: "string", description: "Capability or action the persona wants." },
|
|
10959
10957
|
so_that: { type: "string", description: "Benefit or outcome the persona expects." },
|
|
@@ -11515,7 +11513,7 @@ var UPG_FRAMEWORKS = [
|
|
|
11515
11513
|
},
|
|
11516
11514
|
{
|
|
11517
11515
|
"label": "User Stories",
|
|
11518
|
-
"entityTypeId": "
|
|
11516
|
+
"entityTypeId": "user_story",
|
|
11519
11517
|
"description": "Detailed stories prioritised vertically"
|
|
11520
11518
|
},
|
|
11521
11519
|
{
|
|
@@ -11535,7 +11533,7 @@ var UPG_FRAMEWORKS = [
|
|
|
11535
11533
|
"role": "bucket"
|
|
11536
11534
|
},
|
|
11537
11535
|
{
|
|
11538
|
-
"type": "
|
|
11536
|
+
"type": "user_story",
|
|
11539
11537
|
"role": "bucket"
|
|
11540
11538
|
},
|
|
11541
11539
|
{
|
|
@@ -16276,7 +16274,7 @@ var PRODUCT_DELIVERY_PLAYBOOK = {
|
|
|
16276
16274
|
seqStep(
|
|
16277
16275
|
3,
|
|
16278
16276
|
"Stories",
|
|
16279
|
-
["
|
|
16277
|
+
["user_story", "acceptance_criterion"],
|
|
16280
16278
|
'Write each feature from the user perspective. "As [persona], I want [job], so that [outcome]." Define acceptance criteria.'
|
|
16281
16279
|
),
|
|
16282
16280
|
seqStep(
|
|
@@ -17717,19 +17715,19 @@ var PRODUCT_SPEC_GUIDE = {
|
|
|
17717
17715
|
// registered to product_spec but missing from the navigation order).
|
|
17718
17716
|
// `changelog` lives here because it is a structural product-shipping
|
|
17719
17717
|
// artefact; content domain references it only via cross-domain bridges.
|
|
17720
|
-
creation_sequence: ["feature_area", "feature", "epic", "
|
|
17718
|
+
creation_sequence: ["feature_area", "feature", "epic", "user_story", "acceptance_criterion", "task", "bug", "release", "roadmap", "roadmap_item", "theme", "changelog"],
|
|
17721
17719
|
patterns: [
|
|
17722
17720
|
{
|
|
17723
17721
|
name: "Feature Decomposition",
|
|
17724
|
-
description: "Features group into areas, decompose into epics, epics specify
|
|
17725
|
-
entity_types: ["feature_area", "feature", "epic", "
|
|
17726
|
-
edge_chain: ["feature_area_contains_feature", "feature_decomposed_into_epic", "
|
|
17722
|
+
description: "Features group into areas, decompose into epics, epics specify user stories (the templated promise), and tasks implement them as the engineering work",
|
|
17723
|
+
entity_types: ["feature_area", "feature", "epic", "user_story", "task"],
|
|
17724
|
+
edge_chain: ["feature_area_contains_feature", "feature_decomposed_into_epic", "epic_specified_by_user_story", "task_implements_user_story"]
|
|
17727
17725
|
}
|
|
17728
17726
|
],
|
|
17729
17727
|
required_bridges: [
|
|
17730
17728
|
{ edge_type: "feature_tests_hypothesis", target_domain: "validation", when: "Features should trace back to validated hypotheses" },
|
|
17731
17729
|
{ edge_type: "outcome_delivered_by_feature", target_domain: "strategy", when: "Every feature should connect to a strategic outcome" },
|
|
17732
|
-
{ edge_type: "
|
|
17730
|
+
{ edge_type: "test_case_covers_user_story", target_domain: "testing", when: "User stories should have acceptance tests" }
|
|
17733
17731
|
],
|
|
17734
17732
|
anti_patterns: [
|
|
17735
17733
|
{ description: "Features without outcomes. Features serve strategic outcomes; the rest is waste." },
|
|
@@ -17910,7 +17908,7 @@ var TESTING_GUIDE = {
|
|
|
17910
17908
|
}
|
|
17911
17909
|
],
|
|
17912
17910
|
required_bridges: [
|
|
17913
|
-
{ edge_type: "
|
|
17911
|
+
{ 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)" },
|
|
17914
17912
|
{ edge_type: "test_case_validates_acceptance_criterion", target_domain: "product_spec", when: 'Acceptance criteria define what "done" means and must be validated by tests' }
|
|
17915
17913
|
],
|
|
17916
17914
|
anti_patterns: [
|
|
@@ -19555,7 +19553,7 @@ var UPG_COUNT_BENCHMARKS = [
|
|
|
19555
19553
|
"rationale": "Epics group related stories. Not needed at idea stage."
|
|
19556
19554
|
},
|
|
19557
19555
|
{
|
|
19558
|
-
"type": "
|
|
19556
|
+
"type": "user_story",
|
|
19559
19557
|
"domain": "product_spec",
|
|
19560
19558
|
"concept": null,
|
|
19561
19559
|
"validation": {
|
|
@@ -20470,7 +20468,7 @@ var UPG_RATIO_BENCHMARKS = [
|
|
|
20470
20468
|
},
|
|
20471
20469
|
{
|
|
20472
20470
|
"name": "Story coverage",
|
|
20473
|
-
"numerator_type": "
|
|
20471
|
+
"numerator_type": "user_story",
|
|
20474
20472
|
"denominator_type": "feature",
|
|
20475
20473
|
"expected_min": 2,
|
|
20476
20474
|
"stages": [
|
|
@@ -22253,7 +22251,7 @@ var UPG_REGIONS = [
|
|
|
22253
22251
|
"feature_affected_by_bug",
|
|
22254
22252
|
"epic_specified_by_user_story",
|
|
22255
22253
|
"user_story_verified_by_acceptance_criterion",
|
|
22256
|
-
"
|
|
22254
|
+
"task_implements_user_story",
|
|
22257
22255
|
"roadmap_contains_roadmap_item",
|
|
22258
22256
|
"roadmap_categorised_by_theme",
|
|
22259
22257
|
"roadmap_schedules_release",
|