@windyroad/itil 0.27.1 → 0.28.0-preview.304

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.
Files changed (43) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +9 -1
  3. package/bin/wr-itil-reconcile-stories +2 -0
  4. package/bin/wr-itil-reconcile-story-maps +2 -0
  5. package/hooks/hooks.json +4 -0
  6. package/hooks/itil-readme-refresh-discipline.sh +118 -0
  7. package/hooks/lib/readme-refresh-detect.sh +161 -0
  8. package/hooks/test/itil-readme-refresh-discipline.bats +261 -0
  9. package/lib/migrate-problems-layout.sh +128 -0
  10. package/package.json +1 -1
  11. package/scripts/reconcile-stories.sh +236 -0
  12. package/scripts/reconcile-story-maps.sh +98 -0
  13. package/scripts/test/reconcile-stories.bats +173 -0
  14. package/scripts/test/reconcile-story-maps.bats +74 -0
  15. package/scripts/test/rfc-stories-extension.bats +173 -0
  16. package/scripts/test/update-problem-references-section.bats +195 -0
  17. package/scripts/test/update-references-section-sibling-helpers.bats +80 -0
  18. package/scripts/test/working-the-problem-traversal.bats +109 -0
  19. package/scripts/update-jtbd-references-section.sh +131 -0
  20. package/scripts/update-problem-references-section.sh +284 -0
  21. package/scripts/update-rfc-references-section.sh +152 -0
  22. package/scripts/update-story-references-section.sh +128 -0
  23. package/skills/capture-rfc/SKILL.md +28 -3
  24. package/skills/capture-story/SKILL.md +373 -0
  25. package/skills/capture-story/test/capture-story-behavioural.bats +227 -0
  26. package/skills/capture-story-map/SKILL.md +229 -0
  27. package/skills/capture-story-map/test/capture-story-map-behavioural.bats +98 -0
  28. package/skills/list-stories/SKILL.md +151 -0
  29. package/skills/list-stories/test/list-stories-contract.bats +127 -0
  30. package/skills/list-story-maps/SKILL.md +93 -0
  31. package/skills/list-story-maps/test/list-story-maps-contract.bats +46 -0
  32. package/skills/manage-problem/SKILL.md +42 -4
  33. package/skills/manage-problem/test/manage-problem-auto-migrate-step.bats +53 -0
  34. package/skills/manage-rfc/SKILL.md +12 -0
  35. package/skills/manage-story/SKILL.md +242 -0
  36. package/skills/manage-story/test/manage-story-contract.bats +171 -0
  37. package/skills/manage-story-map/SKILL.md +158 -0
  38. package/skills/manage-story-map/test/manage-story-map-contract.bats +63 -0
  39. package/skills/reconcile-stories/SKILL.md +110 -0
  40. package/skills/reconcile-story-maps/SKILL.md +70 -0
  41. package/skills/work-problem/SKILL.md +1 -1
  42. package/skills/work-problems/SKILL.md +25 -0
  43. package/skills/work-problems/test/work-problems-auto-migrate-step.bats +57 -0
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: wr-itil:list-stories
3
+ description: List INVEST-shaped story tickets from docs/stories/ as a markdown table. Read-only display — no edits, no interaction. Optional `--rfc RFC-<NNN>` filter to surface a specific RFC's ordered story list per ADR-060 Phase 2.
4
+ allowed-tools: Read, Bash, Grep, Glob
5
+ ---
6
+
7
+ # List Stories
8
+
9
+ Display the story corpus from `docs/stories/` as a markdown table. Read-only view of the story tier per ADR-060 Phase 2; this skill does not edit, transition, close, or create stories. For those operations, use the dedicated skills (`/wr-itil:capture-story`, `/wr-itil:manage-story`).
10
+
11
+ Mirrors the `/wr-itil:list-problems` precedent (P071 phased-landing split per ADR-010 amended Skill Granularity rule: one skill per distinct user intent). The list-stories surface separates the read-only view from the heavyweight `/wr-itil:manage-story list` subcommand route (which is itself a candidate for phased-landing split in a future slice).
12
+
13
+ ## Scope
14
+
15
+ Stories live under `docs/stories/<state>/STORY-<NNN>-<slug>.md` in lifecycle subdirectories:
16
+
17
+ - `docs/stories/draft/*.md` — draft (captured via `/wr-itil:capture-story`; pre-INVEST-acceptance)
18
+ - `docs/stories/accepted/*.md` — accepted (INVEST-shape verified per I10; pre-implementation)
19
+ - `docs/stories/in-progress/*.md` — in-progress (implementation underway; auto-transitioned from accepted on first `Refs: STORY-<NNN>` commit AFTER the capture commit per ADR-060 line 292)
20
+ - `docs/stories/done/*.md` — done (acceptance-criteria all-ticked + linked RFC closes; auto-transitioned from in-progress)
21
+ - `docs/stories/archived/*.md` — archived (closed without completion; manual transition)
22
+
23
+ Per ADR-060 I11 invariant (Phase 2 deferred): stories MUST NOT carry a WSJF field. Ordering inside an RFC is per the RFC's frontmatter `stories: [STORY-<NNN>, ...]` array (ordered = execution sequence per ADR-060 line 259), NOT per any per-story WSJF.
24
+
25
+ ## Argument grammar
26
+
27
+ **Positional (optional)**: `--rfc RFC-<NNN>` flag-style filter. When provided, the display lists ONLY stories that trace to the named RFC, IN THE ORDER specified by the RFC's frontmatter `stories:` array per ADR-060 line 259. Without the flag, all stories across all lifecycle states are listed grouped by state.
28
+
29
+ ```
30
+ /wr-itil:list-stories # All stories, grouped by lifecycle state
31
+ /wr-itil:list-stories --rfc RFC-002 # Only stories under RFC-002, in execution order
32
+ ```
33
+
34
+ ## Steps
35
+
36
+ ### 1. Check `docs/stories/README.md` cache freshness
37
+
38
+ Reuse the same `git log`-based freshness test as `/wr-itil:list-problems` Step 1 (per P031 — filesystem mtime is unreliable in worktrees and fresh checkouts):
39
+
40
+ ```bash
41
+ readme_commit=$(git log -1 --format=%H -- docs/stories/README.md 2>/dev/null)
42
+ if [ -z "$readme_commit" ] || \
43
+ git log --oneline "${readme_commit}..HEAD" -- 'docs/stories/*/*.md' ':!docs/stories/README.md' 2>/dev/null | grep -q .; then
44
+ echo "stale"
45
+ fi
46
+ ```
47
+
48
+ **Cache fresh** (no output AND no `--rfc` filter): read `docs/stories/README.md` directly — display the Story Rankings section + Done section as-is. Note in the output: "Using cached ranking from [timestamp in README.md]".
49
+
50
+ **Cache stale OR `--rfc` filter provided OR `README.md` missing**: run the live scan in Step 2. (The filter case always live-scans because the README cache is whole-corpus ranking, not a per-RFC filtered view.)
51
+
52
+ ### 2. Live scan (cache-stale fallback OR filter mode)
53
+
54
+ **Unfiltered live scan** — enumerate every state directory:
55
+
56
+ ```bash
57
+ ls docs/stories/draft/*.md docs/stories/accepted/*.md docs/stories/in-progress/*.md docs/stories/done/*.md docs/stories/archived/*.md 2>/dev/null
58
+ ```
59
+
60
+ For each story file, parse the YAML frontmatter to extract: `story-id`, `status`, `problems`, `jtbd`, `rfcs`, `story-maps`, `estimated-effort`. Read the H1 line for the title.
61
+
62
+ **Filtered live scan** (`--rfc RFC-<NNN>` provided) — resolve the RFC file first, then enumerate its ordered `stories:` array:
63
+
64
+ ```bash
65
+ rfc_file=$(ls docs/rfcs/RFC-<NNN>-*.md 2>/dev/null | head -1)
66
+ [ -z "$rfc_file" ] && echo "RFC-<NNN> not found" >&2 && exit 1
67
+
68
+ # Extract the ordered stories: array from RFC frontmatter
69
+ # (Phase 2 Slice 11 extension — see ADR-060 RFC frontmatter extension)
70
+ stories_list=$(awk '/^stories:/,/^[a-z]/' "$rfc_file" | grep -oE 'STORY-[0-9]+')
71
+ ```
72
+
73
+ For each `STORY-<NNN>` in the ordered list, resolve to a file under `docs/stories/*/STORY-<NNN>-*.md` and parse the frontmatter as above. Preserve the RFC's array ordering in the output.
74
+
75
+ ### 3. Display
76
+
77
+ **Unfiltered mode** — render lifecycle-grouped sections:
78
+
79
+ ```markdown
80
+ ## Draft
81
+
82
+ | ID | Title | Problems | JTBD | RFCs | Story Maps |
83
+ |----|-------|----------|------|------|------------|
84
+ | STORY-<NNN> | <title> | <P<NNN>...> | <JTBD-<NNN>...> | <RFC-<NNN>...> | <STORY-MAP-<NNN>...> |
85
+
86
+ ## Accepted
87
+
88
+ | ID | Title | Problems | JTBD | RFCs | Story Maps | Effort |
89
+ |----|-------|----------|------|------|------------|--------|
90
+ ...
91
+
92
+ ## In Progress
93
+
94
+ (same shape as Accepted)
95
+
96
+ ## Done
97
+
98
+ | ID | Title | Done date | Driving problems |
99
+ |----|-------|-----------|------------------|
100
+ ...
101
+ ```
102
+
103
+ Omit empty sections rather than rendering empty headers. The Estimated Effort column is omitted from the Draft section because effort is deferred at capture and only required at accepted per I10 INVEST Estimable.
104
+
105
+ **Filtered mode** (`--rfc RFC-<NNN>`) — render a single ordered table:
106
+
107
+ ```markdown
108
+ ## Stories under RFC-<NNN>
109
+
110
+ (In execution order per RFC frontmatter `stories:` array.)
111
+
112
+ | Order | ID | Title | Status | Effort |
113
+ |-------|----|-------|--------|--------|
114
+ | 1 | STORY-<NNN> | <title> | <status> | <effort> |
115
+ | 2 | STORY-<NNN> | <title> | <status> | <effort> |
116
+ ...
117
+ ```
118
+
119
+ The Order column makes the execution sequence visible — critical for the working-the-problem flow per ADR-060 line 314 ("read frontmatter `stories:` array (ordered) → pick first not-done story").
120
+
121
+ ### 4. Trailing suggestions
122
+
123
+ After the table(s), print one short pointer depending on output:
124
+
125
+ - **Filtered mode + first not-done story exists**: `Run /wr-itil:work-problem to advance the next story under RFC-<NNN> (STORY-<NNN> — <title>).` (Note: working-the-problem traversal per ADR-060 line 300-320 lands in Slice 13.)
126
+ - **Filtered mode + all stories done**: `All stories under RFC-<NNN> are done. Run /wr-itil:manage-rfc <RFC-<NNN>> verifying to transition the RFC.`
127
+ - **Unfiltered mode + Draft section non-empty**: `Run /wr-itil:manage-story <STORY-<NNN>> accepted to advance a draft through INVEST gates.`
128
+ - **Unfiltered mode + only Done section non-empty**: `No active stories. Run /wr-itil:capture-story to draft a new story.`
129
+
130
+ ## Ownership boundary
131
+
132
+ `list-stories` does not modify, rename, or commit any files. If the README.md cache is stale, list-stories performs a live scan but does NOT rewrite `docs/stories/README.md` — refreshing the cache is `/wr-itil:manage-story review`'s ownership (Slice 8 lands the review surface). The trailing-suggestion pointer surfaces this boundary.
133
+
134
+ ## Related
135
+
136
+ - **ADR-060** — Problem-RFC-Story framework + Phase 2 amendment 2026-05-12 (story tier).
137
+ - **ADR-060 line 259** — RFC frontmatter `stories:` ORDERED array (execution sequence).
138
+ - **ADR-060 line 294** — `/wr-itil:list-stories` skill description with `--rfc RFC-<NNN>` filter.
139
+ - **ADR-060 lines 300-320** — working-the-problem flow (Slice 13 lands the traversal).
140
+ - **ADR-060 line 253** — I11 no-WSJF-leak invariant (Phase 2).
141
+ - **P071** — phased-landing split precedent (list-problems split from manage-problem list).
142
+ - **ADR-010 amended** — Skill Granularity rule.
143
+ - **ADR-022** — lifecycle conventions (story lifecycle mirrors problem lifecycle).
144
+ - **ADR-037** — contract-assertion bats pattern.
145
+ - **P031** — git-history freshness check rationale.
146
+ - **JTBD-008** — Decompose a Fix Into Coordinated Changes. The list view supports the working-the-problem flow that operationalises JTBD-008's "first-class entity" Desired Outcome.
147
+ - **JTBD-006** — Progress the Backlog While I'm Away. Filtered mode (`--rfc`) feeds the AFK orchestrator's per-RFC iter dispatch (Slice 13).
148
+ - `packages/itil/skills/list-problems/SKILL.md` — direct precedent shape.
149
+ - `packages/itil/skills/list-incidents/SKILL.md` — sibling list-* skill at the incident tier.
150
+
151
+ $ARGUMENTS
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env bats
2
+ # Behavioural contract fixtures for /wr-itil:list-stories (P170 Phase 2 Slice 10).
3
+ #
4
+ # Per ADR-037 + ADR-052: behavioural tests over structural prose-grep.
5
+ # These tests exercise the read-only display surface contract — read
6
+ # story files, render markdown tables, no edits.
7
+ #
8
+ # Behavioural surfaces under test:
9
+ # 1. SKILL.md presence + canonical name (minimum discoverability).
10
+ # 2. Read-only contract — no Write/Edit tools in frontmatter.
11
+ # 3. Lifecycle enumeration — list-stories enumerates all five state
12
+ # subdirectories (draft / accepted / in-progress / done / archived).
13
+ # 4. RFC-filter ordering — when --rfc filter is provided, ordering
14
+ # follows the RFC frontmatter `stories:` array, not lexical /
15
+ # filesystem order.
16
+ #
17
+ # @problem P170
18
+ # @jtbd JTBD-008 (Decompose a Fix Into Coordinated Changes — list view
19
+ # supports the working-the-problem flow's per-RFC iter
20
+ # dispatch in Slice 13)
21
+ # @jtbd JTBD-006 (Progress the Backlog While I'm Away — filtered mode
22
+ # feeds the AFK orchestrator)
23
+ # @adr ADR-060 (Problem-RFC-Story framework — story tier line 294
24
+ # list-stories description)
25
+ # @adr ADR-037 (Skill testing strategy — contract bats)
26
+ # @adr ADR-052 (Behavioural-tests-default)
27
+ # @adr ADR-010 (Amended skill granularity — phased-landing split
28
+ # precedent from list-problems / P071)
29
+
30
+ setup() {
31
+ REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
32
+ SKILL_FILE="${REPO_ROOT}/packages/itil/skills/list-stories/SKILL.md"
33
+
34
+ TMPROOT=$(mktemp -d)
35
+ ORIG_DIR="$PWD"
36
+ cd "$TMPROOT"
37
+ # Set up minimal story corpus fixture
38
+ mkdir -p docs/stories/draft docs/stories/accepted docs/stories/in-progress docs/stories/done docs/stories/archived
39
+ mkdir -p docs/rfcs
40
+ }
41
+
42
+ teardown() {
43
+ cd "$ORIG_DIR"
44
+ rm -rf "$TMPROOT"
45
+ }
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # Surface 0: SKILL.md exists with correct name (minimum discoverability)
49
+ # ---------------------------------------------------------------------------
50
+
51
+ @test "list-stories: SKILL.md exists" {
52
+ [ -f "$SKILL_FILE" ]
53
+ }
54
+
55
+ @test "list-stories: SKILL.md frontmatter declares wr-itil:list-stories name" {
56
+ run grep -E '^name: wr-itil:list-stories$' "$SKILL_FILE"
57
+ [ "$status" -eq 0 ]
58
+ }
59
+
60
+ # ---------------------------------------------------------------------------
61
+ # Surface 1: Read-only contract — no Write/Edit in allowed-tools
62
+ # (ADR-010 phased-landing split rule: list-* skills are pure read views)
63
+ # ---------------------------------------------------------------------------
64
+
65
+ @test "list-stories: SKILL.md allowed-tools does NOT include Write or Edit" {
66
+ # Behavioural: extract the allowed-tools line and check it omits the
67
+ # write tools. The list-* family is read-only by contract per ADR-010.
68
+ run grep '^allowed-tools:' "$SKILL_FILE"
69
+ [ "$status" -eq 0 ]
70
+ [[ "$output" != *"Write"* ]]
71
+ [[ "$output" != *"Edit"* ]]
72
+ }
73
+
74
+ # ---------------------------------------------------------------------------
75
+ # Surface 2: Lifecycle enumeration — all 5 state subdirectories
76
+ # (story lifecycle per ADR-060 mirrors problem lifecycle ADR-022)
77
+ # ---------------------------------------------------------------------------
78
+
79
+ @test "list-stories: SKILL.md names all 5 lifecycle state subdirectories" {
80
+ # The Scope section enumerates the lifecycle states. Without all five,
81
+ # the list view would miss stories in some lifecycle state silently —
82
+ # a behavioural defect not a prose preference.
83
+ for state in draft accepted in-progress done archived; do
84
+ run grep -E "docs/stories/${state}" "$SKILL_FILE"
85
+ [ "$status" -eq 0 ]
86
+ done
87
+ }
88
+
89
+ # ---------------------------------------------------------------------------
90
+ # Surface 3: --rfc filter ordering follows RFC frontmatter `stories:` array
91
+ # (load-bearing for the working-the-problem flow per ADR-060 line 314)
92
+ # ---------------------------------------------------------------------------
93
+
94
+ @test "list-stories: --rfc filter mode enumerates stories via RFC frontmatter stories array" {
95
+ # The SKILL.md filter-mode pseudocode reads the RFC's frontmatter and
96
+ # extracts STORY-NNN tokens in order. This is the load-bearing
97
+ # behaviour for Slice 13's working-the-problem traversal — verify
98
+ # the SKILL prescribes RFC-frontmatter-driven order, not filesystem
99
+ # / lexical order.
100
+ run grep -E 'stories_list.*RFC|stories: array|RFC frontmatter' "$SKILL_FILE"
101
+ [ "$status" -eq 0 ]
102
+ }
103
+
104
+ # ---------------------------------------------------------------------------
105
+ # Surface 4: Cache-freshness check pattern — same git log shape as list-problems
106
+ # (P031: filesystem mtime unreliable in worktrees; git history is authoritative)
107
+ # ---------------------------------------------------------------------------
108
+
109
+ @test "list-stories: SKILL.md uses git log cache-freshness pattern per P031" {
110
+ run grep -E 'git log -1 --format=%H -- docs/stories/README\.md' "$SKILL_FILE"
111
+ [ "$status" -eq 0 ]
112
+ }
113
+
114
+ # ---------------------------------------------------------------------------
115
+ # Surface 5: No-WSJF-leak — I11 invariant
116
+ # (ADR-060 line 253: stories MUST NOT carry a WSJF field in Phase 2)
117
+ # ---------------------------------------------------------------------------
118
+
119
+ @test "list-stories: SKILL.md does NOT render a WSJF column (I11 invariant)" {
120
+ # Phase 2 invariant: no story-level WSJF. The display tables must
121
+ # not include a WSJF column header. This is a behavioural contract
122
+ # at the SKILL output surface, not a prose-grep.
123
+ # The output tables specified in SKILL.md should have NO 'WSJF' header.
124
+ # Find any markdown table header line and verify none include WSJF.
125
+ run grep -E '^\| WSJF\b|\| WSJF \|' "$SKILL_FILE"
126
+ [ "$status" -ne 0 ]
127
+ }
@@ -0,0 +1,93 @@
1
+ ---
2
+ name: wr-itil:list-story-maps
3
+ description: List story-map artefacts from docs/story-maps/ as a markdown table. Read-only display — no edits, no interaction. Renders <meta> block data (problems / rfcs / jtbd / status) from each HTML map per ADR-060 § Phase 2 encoding amendment 2026-05-12.
4
+ allowed-tools: Read, Bash, Grep, Glob
5
+ ---
6
+
7
+ # List Story Maps
8
+
9
+ Display the story-map corpus from `docs/story-maps/` as a markdown table. Read-only view per ADR-060 Phase 2; does not edit, transition, or create maps.
10
+
11
+ Mirrors `/wr-itil:list-stories` precedent (P071 phased-landing split per ADR-010). I5 invariant: story-maps MUST NOT carry WSJF (no Story Rankings table — maps are planning artefacts, not work items per ADR-060 line 145).
12
+
13
+ ## Scope
14
+
15
+ Story-maps live under `docs/story-maps/<state>/STORY-MAP-<NNN>-<slug>.html`:
16
+ - `draft/` — captured (problem + JTBD traces present); pre-acceptance authoring
17
+ - `accepted/` — backbone/ribs/slices authored; ready for implementation dispatch
18
+ - `in-progress/` — slices being implemented; stories transitioning
19
+ - `completed/` — all slices done
20
+ - `archived/` — closed without completion
21
+
22
+ ## Argument grammar
23
+
24
+ No arguments (read-only display).
25
+
26
+ ## Steps
27
+
28
+ ### 1. Check `docs/story-maps/README.md` cache freshness
29
+
30
+ ```bash
31
+ readme_commit=$(git log -1 --format=%H -- docs/story-maps/README.md 2>/dev/null)
32
+ if [ -z "$readme_commit" ] || \
33
+ git log --oneline "${readme_commit}..HEAD" -- 'docs/story-maps/*/*.html' ':!docs/story-maps/README.md' 2>/dev/null | grep -q .; then
34
+ echo "stale"
35
+ fi
36
+ ```
37
+
38
+ **Cache fresh**: read `docs/story-maps/README.md` directly. **Cache stale**: live-scan in Step 2.
39
+
40
+ ### 2. Live scan
41
+
42
+ Enumerate each lifecycle subdir:
43
+
44
+ ```bash
45
+ ls docs/story-maps/draft/*.html docs/story-maps/accepted/*.html docs/story-maps/in-progress/*.html docs/story-maps/completed/*.html docs/story-maps/archived/*.html 2>/dev/null
46
+ ```
47
+
48
+ For each map file, parse the `<meta>` block to extract: `story-map-id`, `status`, `problems`, `rfcs`, `jtbd`. Use `xmllint --xpath` when available; fall back to `grep` on `<meta>` lines:
49
+
50
+ ```bash
51
+ status=$(xmllint --xpath 'string(//meta[@name="status"]/@content)' "$map" 2>/dev/null || \
52
+ grep -oE '<meta name="status" content="[^"]*"' "$map" | grep -oE 'content="[^"]*"' | sed 's/content="//;s/"$//')
53
+ ```
54
+
55
+ ### 3. Display
56
+
57
+ Render lifecycle-grouped sections:
58
+
59
+ ```markdown
60
+ ## Draft
61
+
62
+ | ID | Title | Problems | RFCs | JTBD |
63
+ |----|-------|----------|------|------|
64
+ | STORY-MAP-<NNN> | <title> | <P<NNN>...> | <RFC-<NNN>...> | <JTBD-<NNN>...> |
65
+
66
+ ## Accepted / In Progress / Completed / Archived
67
+
68
+ (same shape; sections omitted when empty)
69
+ ```
70
+
71
+ NO WSJF column per I5. NO ranking table per the "story-maps are planning artefacts, not work items" principle (ADR-060 line 145).
72
+
73
+ ### 4. Trailing suggestions
74
+
75
+ - Draft section non-empty: `Run /wr-itil:manage-story-map <STORY-MAP-<NNN>> accepted to author backbone/ribs/slices and advance the draft.`
76
+ - In-progress section non-empty: `Run /wr-itil:list-stories --rfc <RFC-<NNN>> to see the next story under each in-progress map's referenced RFC.`
77
+ - All sections empty: `No story maps captured yet. Run /wr-itil:capture-story-map <P-<NNN>> <JTBD-<NNN>> <description> to capture the first.`
78
+
79
+ ## Ownership boundary
80
+
81
+ Does not modify, rename, or commit files. Cache-stale path performs live scan only; never rewrites `docs/story-maps/README.md` — refresh is `/wr-itil:manage-story-map review`'s ownership.
82
+
83
+ ## Related
84
+
85
+ - **ADR-060** — Problem-RFC-Story framework; Phase 2 amendment lines 145-189 (story-map tier spec).
86
+ - **ADR-060 line 145** — story-maps are planning artefacts; no WSJF (I5).
87
+ - **ADR-060 lines 381-435** — HTML encoding schema; `<meta>` block parse target.
88
+ - **`docs/story-maps/README.md`** — story-map directory index.
89
+ - **`/wr-itil:list-stories`** — sibling read-only display at the story tier.
90
+ - **`/wr-itil:list-problems`** — sibling at the problem tier (P071 precedent).
91
+ - **JTBD-008** — Decompose a Fix Into Coordinated Changes.
92
+
93
+ $ARGUMENTS
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bats
2
+ # Behavioural contract fixtures for /wr-itil:list-story-maps (P170 Phase 2 Slice 6).
3
+
4
+ setup() {
5
+ REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
6
+ SKILL_FILE="${REPO_ROOT}/packages/itil/skills/list-story-maps/SKILL.md"
7
+ }
8
+
9
+ @test "list-story-maps: SKILL.md exists" {
10
+ [ -f "$SKILL_FILE" ]
11
+ }
12
+
13
+ @test "list-story-maps: SKILL.md frontmatter declares wr-itil:list-story-maps name" {
14
+ run grep -E '^name: wr-itil:list-story-maps$' "$SKILL_FILE"
15
+ [ "$status" -eq 0 ]
16
+ }
17
+
18
+ @test "list-story-maps: SKILL.md allowed-tools does NOT include Write or Edit (read-only contract)" {
19
+ run grep '^allowed-tools:' "$SKILL_FILE"
20
+ [ "$status" -eq 0 ]
21
+ [[ "$output" != *"Write"* ]]
22
+ [[ "$output" != *"Edit"* ]]
23
+ }
24
+
25
+ @test "list-story-maps: SKILL.md names all 5 lifecycle state subdirectories" {
26
+ for state in draft accepted in-progress completed archived; do
27
+ run grep -E "docs/story-maps/${state}|${state}/" "$SKILL_FILE"
28
+ [ "$status" -eq 0 ]
29
+ done
30
+ }
31
+
32
+ @test "list-story-maps: SKILL.md does NOT render a WSJF column (I5 invariant)" {
33
+ # Story-maps are planning artefacts, not work items — no WSJF per ADR-060 line 145.
34
+ run grep -E '^\| WSJF\b|\| WSJF \|' "$SKILL_FILE"
35
+ [ "$status" -ne 0 ]
36
+ }
37
+
38
+ @test "list-story-maps: SKILL.md names <meta> block parse target per ADR-060 lines 381-435" {
39
+ run grep -E '<meta name=|xmllint.*meta' "$SKILL_FILE"
40
+ [ "$status" -eq 0 ]
41
+ }
42
+
43
+ @test "list-story-maps: SKILL.md uses git log cache-freshness pattern per P031" {
44
+ run grep -E 'git log -1 --format=%H -- docs/story-maps/README\.md' "$SKILL_FILE"
45
+ [ "$status" -eq 0 ]
46
+ }
@@ -166,10 +166,23 @@ What "work" means depends on the problem's status:
166
166
  8. If the fix is small enough, continue straight to implementing it (becoming a Known Error → Closed flow in one session)
167
167
 
168
168
  **Known Error (root cause confirmed, fix path clear):**
169
- 1. Read the root cause analysis and fix strategy
170
- 2. Implement the fix following the project's development workflow (plan if needed, architect review, tests, etc.)
171
- 3. Include the problem doc closure in the fix commit (`git mv` to `.closed.md`, update Status)
172
- 4. Push, create changeset, release per the lean release principle
169
+
170
+ The Phase 2 working-the-problem traversal makes "implement the fix" concretely traceable via stories (per ADR-060 lines 300-320). Replaces the prior vague "implement the fix following the project's development workflow" with a deterministic problem RFC → story dispatch:
171
+
172
+ 1. **Read the problem's `## Fix Strategy` section** — extract referenced RFC IDs (anchor links / inline references like `RFC-NNN`). If no RFCs are referenced, the problem is non-decomposed Phase 1 work: fall through to the legacy direct-implementation path (step 6 below).
173
+ 2. **For each referenced RFC** (in the order they appear in the Fix Strategy section), read its frontmatter `stories:` array (per ADR-060 line 259, the array is ORDERED — array position IS execution sequence):
174
+ - **Non-empty `stories:` array** (story-decomposed RFC): pick the first story whose lifecycle status is `accepted` or `in-progress` — skip `done` stories that already shipped, skip `draft` stories that aren't ready (the `manage-story <NNN> accepted` gate enforces INVEST shape; a draft story is structurally unready). Continue to step 3.
175
+ - **Empty `stories: []`** (atomic RFC per JTBD-101 friction guard, ADR-060 line 262): fall back to Phase 1 per-RFC iter dispatch — read the RFC body's `## Tasks` section directly; pick the first unticked task; no per-story scoping needed. Skip to step 5 (commit + trailer).
176
+ 3. **Read the picked story's body** — `## User value` statement (INVEST Valuable), `## Acceptance criteria` (INVEST Testable observable behaviours), `## Implementation notes` (architecture sketches, library decisions). The story's frontmatter `estimated-effort` field (set at `manage-story accepted` transition per I10 INVEST Estimable) sets the appetite for the iteration.
177
+ 4. **Implement the story scope** — follow the project's standard development workflow (plan if needed, architect/JTBD review, behavioural tests per ADR-052, single-commit grain per ADR-014). Confine the implementation to the picked story's acceptance criteria; deviating into adjacent unscoped work is a scope-expansion signal — surface it via the `## Scope expansion` AskUserQuestion below.
178
+ 5. **Commit with the `Refs: STORY-<NNN>` trailer** (single-trailer vocabulary per ADR-060 line 307 + amendment 2026-05-10 nitpick N2 — same trailer verb whether the commit is the story's first implementation commit or a continuation). On the FIRST commit AFTER the capture commit (subject prefix discriminates: `feat(itil): capture STORY-NNN ...` is the capture; any other subject prefix is an implementation commit), `/wr-itil:manage-story` auto-transitions the story `draft → in-progress`. As acceptance criteria checkboxes are ticked across multiple commits, the same trailer continues to attribute the work.
179
+ 6. **Story `done` auto-transition**: when ALL acceptance-criteria checkboxes in the story body are ticked AND the linked RFC reaches `closed`, `/wr-itil:manage-story` auto-transitions the story `in-progress → done`. (When a story's RFC is still `in-progress` but the acceptance criteria are all ticked, the story stays at `in-progress` until the RFC closes — this preserves the trace coupling per ADR-060 line 309.)
180
+ 7. **Pick the next not-done story** from the RFC's `stories:` array (or the next unticked task from the RFC body for the atomic-RFC fallback path). Repeat from step 3.
181
+ 8. **When all stories under all referenced RFCs are done** — the problem is fix-released. Include the problem doc closure in the final commit (`git mv` to `.verifying.md`, update Status) per ADR-022. Push, create changeset, release per the lean release principle.
182
+
183
+ **Atomic-RFC fallback path** (step 2 empty-stories case, in detail): a Phase 1-shape problem whose Fix Strategy references RFCs that have not been decomposed into stories continues to work via the existing per-RFC iter dispatch — read the RFC body's tasks/steps section, implement each task as a single-commit per ADR-014, attribute via `Refs: RFC-<NNN>` trailer (still single-trailer vocabulary). This preserves Phase 1 atomic-fix-adopter behaviour: an adopter who hasn't adopted Phase 2 story tooling has zero new friction; their RFCs continue to ship with `stories: []` and their problems continue to close via per-RFC iter dispatch.
184
+
185
+ **Legacy direct-implementation path** (step 1 no-RFCs case): a Phase 1-shape Known Error whose Fix Strategy references no RFCs continues to work via the pre-Phase-2 flow — read the root cause analysis and fix strategy, implement the fix following the project's development workflow, include the problem doc closure in the fix commit (`git mv` to `.verifying.md`, update Status), push + changeset + release. This preserves backwards compatibility with all existing Known Error problems (which were captured before the RFC framework was Phase-1-graduated).
173
186
 
174
187
  **Scope expansion during work:** If investigation or architect review reveals that the problem's scope has grown significantly (e.g., effort re-sized from S to L, additional files discovered), use `AskUserQuestion` before continuing:
175
188
  - Option 1: `Continue with expanded scope` — keep working this problem at its new size
@@ -181,6 +194,31 @@ What "work" means depends on the problem's status:
181
194
 
182
195
  ## Steps
183
196
 
197
+ ### 0a. Auto-migrate adopter layout (P170 / RFC-002 / ADR-031)
198
+
199
+ Before the README-reconciliation preflight (Step 0) and any other layout-dependent logic, source the shared shell migration routine and call the idempotent entrypoint:
200
+
201
+ ```bash
202
+ # Source the synced copy from this package's lib/ (canonical lives at
203
+ # packages/shared/lib/migrate-problems-layout.sh per ADR-017 sync pattern).
204
+ source packages/itil/lib/migrate-problems-layout.sh
205
+ migrate_problems_to_per_state_layout "$PWD"
206
+ ```
207
+
208
+ The routine is **idempotent and partial-migration-safe**. It no-ops when no flat-layout files (`docs/problems/*.<state>.md` at the top level of `docs/problems/`) are detected — the common case in this monorepo (post-Slice-5 T5a 2026-05-10) and in freshly-migrated adopter repos.
209
+
210
+ On a flat-layout adopter repo (first invocation post-update — JTBD-101 plugin-developer auto-migration path), the routine:
211
+
212
+ 1. Creates the five state subdirectories (`docs/problems/open/`, `/known-error/`, `/verifying/`, `/parked/`, `/closed/`).
213
+ 2. Runs `git mv docs/problems/<NNN>-<slug>.<state>.md docs/problems/<state>/<NNN>-<slug>.md` for every existing ticket. `nullglob` is enabled so partial-migration tails don't trip on literal-glob expansion.
214
+ 3. Emits a standalone commit (per ADR-031 § Backward Compatibility line 124 "not folded into other work — so adopters can audit / revert in isolation") with subject `docs(problems): auto-migrate to per-state subdirectory layout (ADR-031)` and footer trailer `RISK_BYPASS: adr-031-migration` (recognised by the commit-gate hook per T11; allows the migration to skip the full risk-score overhead while preserving the audit trail).
215
+
216
+ **AFK authorisation per ADR-013 Rule 6**: this fires unconditionally even in AFK / non-interactive / orchestrated mode. Pure-rename + pure-mkdir + standalone-commit actions are policy-authorised under ADR-019 precedent — they are fully reversible (`git revert`), have no external-comms surface, no secrets, no destructive overwrite. No `AskUserQuestion` gate.
217
+
218
+ **First-fire signal (JTBD-006 AFK transparency per T8 jtbd-review nitpick c)**: the routine emits a single stderr line `migrate-problems-layout: relocated N tickets to per-state subdirs (ADR-031)` on the migrating invocation; silent on no-op re-invocations.
219
+
220
+ After Step 0a completes (whether no-op or migration), proceed to Step 0 README reconciliation preflight. The reconcile-readme script reads the post-migration layout; the in-flow Step 5 / Step 7 README refresh paths re-render the README from the per-state subdir shape.
221
+
184
222
  ### 0. README reconciliation preflight (P118)
185
223
 
186
224
  Before parsing the request, run the diagnose-only reconciliation check. The contract here catches **cross-session drift** that per-operation refresh paths (P094 refresh-on-create + P062 refresh-on-transition) cannot retroactively see — if any past session committed a ticket change without staging the README refresh, the next manage-problem invocation reads a stale README that lies about what is open / verifying / closed.
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env bats
2
+
3
+ # P170 / RFC-002 / ADR-031 Open-Execution Q1 resolution: manage-problem
4
+ # SKILL.md wires the shared migration routine at Step 0a (before
5
+ # Step 0 README reconciliation preflight). Doc-lint structural test —
6
+ # the wiring is a SKILL.md preamble integration point; behavioural
7
+ # assertions for the routine itself live at
8
+ # packages/shared/test/sync-migrate-problems-layout.bats (T7) and the
9
+ # end-to-end behavioural fixture
10
+ # packages/itil/skills/manage-problem/test/manage-problem-auto-migrate.bats (T10).
11
+
12
+ setup() {
13
+ REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
14
+ SKILL_MD="$REPO_ROOT/packages/itil/skills/manage-problem/SKILL.md"
15
+ }
16
+
17
+ @test "manage-problem: SKILL.md declares Step 0a auto-migrate (T8 wiring point)" {
18
+ run grep -E '^### 0a\.|^## Step 0a|Step 0a:' "$SKILL_MD"
19
+ [ "$status" -eq 0 ]
20
+ }
21
+
22
+ @test "manage-problem: SKILL.md Step 0a cites P170 / RFC-002 / ADR-031" {
23
+ run grep -F 'P170' "$SKILL_MD"
24
+ [ "$status" -eq 0 ]
25
+ run grep -F 'ADR-031' "$SKILL_MD"
26
+ [ "$status" -eq 0 ]
27
+ }
28
+
29
+ @test "manage-problem: SKILL.md Step 0a sources packages/itil/lib/migrate-problems-layout.sh" {
30
+ run grep -F 'packages/itil/lib/migrate-problems-layout.sh' "$SKILL_MD"
31
+ [ "$status" -eq 0 ]
32
+ }
33
+
34
+ @test "manage-problem: SKILL.md Step 0a calls migrate_problems_to_per_state_layout entrypoint" {
35
+ run grep -F 'migrate_problems_to_per_state_layout' "$SKILL_MD"
36
+ [ "$status" -eq 0 ]
37
+ }
38
+
39
+ @test "manage-problem: SKILL.md Step 0a fires before Step 0 README reconciliation" {
40
+ # Assert the literal line order in the file: Step 0a appears before
41
+ # the existing Step 0 README reconciliation heading.
42
+ local step_0a_line step_0_line
43
+ step_0a_line=$(grep -nE '^### 0a\.|^## Step 0a|Step 0a:' "$SKILL_MD" | head -1 | cut -d: -f1)
44
+ step_0_line=$(grep -nE '^### 0\. README' "$SKILL_MD" | head -1 | cut -d: -f1)
45
+ [ -n "$step_0a_line" ]
46
+ [ -n "$step_0_line" ]
47
+ [ "$step_0a_line" -lt "$step_0_line" ]
48
+ }
49
+
50
+ @test "manage-problem: SKILL.md Step 0a cites ADR-013 Rule 6 (AFK auto-fire authorisation)" {
51
+ run grep -F 'ADR-013' "$SKILL_MD"
52
+ [ "$status" -eq 0 ]
53
+ }
@@ -157,6 +157,18 @@ The helper (`packages/itil/scripts/update-problem-rfcs-section.sh`) is idempoten
157
157
 
158
158
  The trailer hook (`itil-rfc-trailer-advisory.sh`) sits on top of this skill-side contract as a drift-detection backstop for ARBITRARY commits (e.g. `feat(...)` commits with `Refs: RFC-<NNN>` trailers authored outside the RFC skills) — it never auto-fixes; it advises.
159
159
 
160
+ #### Forward trace — `## Stories` body section (Phase 2)
161
+
162
+ Per ADR-060 line 270 + line 296: every transition that touches the RFC body refreshes the RFC's own `## Stories` body section from its frontmatter `stories:` array. The forward-trace surface renders the ordered execution sequence as inline links to the story files, lazy-empty when `stories: []` (atomic RFC — JTBD-101 friction guard). The helper is the Slice 2b sibling `update-rfc-references-section.sh`:
163
+
164
+ ```bash
165
+ bash "$(wr-itil-script-path 2>/dev/null || echo packages/itil/scripts)/update-rfc-references-section.sh" "$rfc_file" "Stories"
166
+ ```
167
+
168
+ Idempotent + lazy-empty per the Slice 2a/2b contract. Run after the rename + frontmatter edit so the section reflects the post-transition `stories:` shape. Stage the RFC file (already staged for the lifecycle transition; the helper modifies the same file in-place).
169
+
170
+ This composes with the existing `## Story Maps` refresh that the same helper handles via `update-rfc-references-section.sh "$rfc_file" "Story Maps"` — when the RFC traces story-maps via the `story-maps:` frontmatter field (Phase 2+).
171
+
160
172
  ### 8. List flow (`list`)
161
173
 
162
174
  Read all `.proposed.md`, `.accepted.md`, `.in-progress.md` files in `docs/rfcs/`. Extract ID, title, status, traced problems. Sort by Status priority (Accepted > In-Progress > Proposed) then by `Reported` ASC. Display as a markdown table.