@windyroad/itil 0.61.1 → 0.61.2

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 (171) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +7 -2
  3. package/agents/test/fixtures/proceed-new-genuinely-new.md +0 -43
  4. package/agents/test/fixtures/proceed-new-subtle-sibling.md +0 -47
  5. package/agents/test/fixtures/regression-p347-vs-p346.md +0 -54
  6. package/agents/test/hang-off-check.bats +0 -225
  7. package/hooks/test/block-list.bats +0 -153
  8. package/hooks/test/command-detect.bats +0 -181
  9. package/hooks/test/itil-assistant-output-gate.bats +0 -114
  10. package/hooks/test/itil-assistant-output-review.bats +0 -224
  11. package/hooks/test/itil-bash-polling-antipattern-detect.bats +0 -154
  12. package/hooks/test/itil-changeset-discipline.bats +0 -603
  13. package/hooks/test/itil-claude-space-protection.bats +0 -294
  14. package/hooks/test/itil-commit-trailer-transition-advisory.bats +0 -80
  15. package/hooks/test/itil-correction-detect.bats +0 -189
  16. package/hooks/test/itil-deferral-cadence-gate.bats +0 -187
  17. package/hooks/test/itil-fictional-defer-detect.bats +0 -292
  18. package/hooks/test/itil-fix-title-lifecycle-advisory.bats +0 -129
  19. package/hooks/test/itil-mid-loop-ask-detect.bats +0 -220
  20. package/hooks/test/itil-no-implement-draft-gate.bats +0 -210
  21. package/hooks/test/itil-pending-questions-surface.bats +0 -307
  22. package/hooks/test/itil-readme-refresh-discipline.bats +0 -642
  23. package/hooks/test/itil-rfc-oversight-nudge.bats +0 -83
  24. package/hooks/test/itil-rfc-trailer-advisory.bats +0 -375
  25. package/hooks/test/itil-story-mirror-migration-nudge.bats +0 -122
  26. package/hooks/test/manage-problem-enforce-create.bats +0 -424
  27. package/hooks/test/p057-staging-trap-detect.bats +0 -231
  28. package/hooks/test/pre-publish-intake-gate.bats +0 -144
  29. package/hooks/test/runtime-sid-marker.bats +0 -90
  30. package/hooks/test/session-id.bats +0 -370
  31. package/scripts/migrate-problems-add-type.sh +0 -116
  32. package/scripts/test/catchup-scan.bats +0 -274
  33. package/scripts/test/check-afk-accept-eligible.bats +0 -310
  34. package/scripts/test/check-fail-soft-skip-discipline.bats +0 -172
  35. package/scripts/test/check-fix-rfc-trace.bats +0 -164
  36. package/scripts/test/check-locale-discipline.bats +0 -291
  37. package/scripts/test/check-problems-readme-budget.bats +0 -192
  38. package/scripts/test/check-rfc-has-stories.bats +0 -69
  39. package/scripts/test/check-rfc-rejected-alternatives.bats +0 -108
  40. package/scripts/test/check-rfc-stories-ratified.bats +0 -82
  41. package/scripts/test/check-upstream-responses.bats +0 -503
  42. package/scripts/test/classify-readme-drift.bats +0 -392
  43. package/scripts/test/derive-first-dispatch.bats +0 -274
  44. package/scripts/test/derive-release-vehicle.bats +0 -454
  45. package/scripts/test/detect-unratified-stories-maps.bats +0 -60
  46. package/scripts/test/dual-tolerant-glob-rfc-002-t2.bats +0 -309
  47. package/scripts/test/effort-tally.bats +0 -170
  48. package/scripts/test/evaluate-relevance.bats +0 -773
  49. package/scripts/test/kind-a-commands.bats +0 -46
  50. package/scripts/test/mark-create-gate.bats +0 -59
  51. package/scripts/test/mark-story-oversight-confirmed.bats +0 -53
  52. package/scripts/test/migrate-problems-add-type.bats +0 -280
  53. package/scripts/test/migrate-story-status-mirror.bats +0 -167
  54. package/scripts/test/no-type-regression-guard.bats +0 -74
  55. package/scripts/test/oversight-mirror-corpus-lint.bats +0 -150
  56. package/scripts/test/plugin-exercise-index.bats +0 -386
  57. package/scripts/test/plugin-maturity-doc-lint.bats +0 -470
  58. package/scripts/test/plugin-maturity-populate.bats +0 -631
  59. package/scripts/test/plugin-maturity-render.bats +0 -469
  60. package/scripts/test/plugin-validate-ci-gate.bats +0 -208
  61. package/scripts/test/reconcile-readme.bats +0 -1007
  62. package/scripts/test/reconcile-rfcs.bats +0 -496
  63. package/scripts/test/reconcile-stories.bats +0 -173
  64. package/scripts/test/reconcile-story-maps.bats +0 -74
  65. package/scripts/test/release-watch-poll-loop.bats +0 -180
  66. package/scripts/test/resolve-governance-plugin-dirs.bats +0 -78
  67. package/scripts/test/rfc-stories-extension.bats +0 -175
  68. package/scripts/test/skill-invocations.bats +0 -535
  69. package/scripts/test/skill-md-dual-tolerant-coverage-rfc-002-t3.bats +0 -374
  70. package/scripts/test/story-oversight-lib.bats +0 -190
  71. package/scripts/test/update-jtbd-references-related-problems.bats +0 -178
  72. package/scripts/test/update-problem-references-section.bats +0 -242
  73. package/scripts/test/update-problem-rfcs-section.bats +0 -242
  74. package/scripts/test/update-references-section-sibling-helpers.bats +0 -80
  75. package/scripts/test/update-rfc-commits-section.bats +0 -77
  76. package/scripts/test/verify-iter-summary.bats +0 -196
  77. package/scripts/test/working-the-problem-traversal.bats +0 -116
  78. package/skills/capture-problem/test/capture-problem-step-1-5b-jtbd-trace.bats +0 -398
  79. package/skills/capture-problem/test/capture-problem.bats +0 -389
  80. package/skills/capture-story/test/capture-story-behavioural.bats +0 -317
  81. package/skills/capture-story-map/test/capture-story-map-behavioural.bats +0 -98
  82. package/skills/close-incident/test/close-incident-contract.bats +0 -146
  83. package/skills/link-incident/test/link-incident-contract.bats +0 -125
  84. package/skills/list-incidents/test/list-incidents-contract.bats +0 -115
  85. package/skills/list-problems/test/list-problems-contract.bats +0 -100
  86. package/skills/list-stories/test/list-stories-contract.bats +0 -127
  87. package/skills/list-story-maps/test/list-story-maps-contract.bats +0 -46
  88. package/skills/manage-incident/test/manage-incident-adr-044-contract.bats +0 -206
  89. package/skills/manage-incident/test/manage-incident-close-forwarder.bats +0 -67
  90. package/skills/manage-incident/test/manage-incident-link-forwarder.bats +0 -67
  91. package/skills/manage-incident/test/manage-incident-list-forwarder.bats +0 -68
  92. package/skills/manage-incident/test/manage-incident-mitigate-forwarder.bats +0 -66
  93. package/skills/manage-incident/test/manage-incident-restore-forwarder.bats +0 -66
  94. package/skills/manage-incident/test/manage-incident.bats +0 -171
  95. package/skills/manage-problem/test/manage-problem-adr-044-step4-derive-first.bats +0 -151
  96. package/skills/manage-problem/test/manage-problem-auto-migrate-step.bats +0 -53
  97. package/skills/manage-problem/test/manage-problem-concern-boundary.bats +0 -64
  98. package/skills/manage-problem/test/manage-problem-effort-buckets.bats +0 -56
  99. package/skills/manage-problem/test/manage-problem-external-root-cause-detection.bats +0 -119
  100. package/skills/manage-problem/test/manage-problem-first-run-intake-prompt.bats +0 -43
  101. package/skills/manage-problem/test/manage-problem-git-mv-restage-reminder.bats +0 -48
  102. package/skills/manage-problem/test/manage-problem-id-collision-guard.bats +0 -39
  103. package/skills/manage-problem/test/manage-problem-list-forwarder.bats +0 -66
  104. package/skills/manage-problem/test/manage-problem-next-id-origin-lookup.bats +0 -50
  105. package/skills/manage-problem/test/manage-problem-no-prose-options.bats +0 -74
  106. package/skills/manage-problem/test/manage-problem-output-formatting.bats +0 -30
  107. package/skills/manage-problem/test/manage-problem-parked-and-cache.bats +0 -73
  108. package/skills/manage-problem/test/manage-problem-readme-refresh-on-transition.bats +0 -62
  109. package/skills/manage-problem/test/manage-problem-readme-tie-break-order.bats +0 -318
  110. package/skills/manage-problem/test/manage-problem-readme-vq-sort-order.bats +0 -206
  111. package/skills/manage-problem/test/manage-problem-release-vehicle-seed.bats +0 -83
  112. package/skills/manage-problem/test/manage-problem-review-forwarder.bats +0 -71
  113. package/skills/manage-problem/test/manage-problem-step-9d-recovery-path.bats +0 -97
  114. package/skills/manage-problem/test/manage-problem-transition-forwarder.bats +0 -96
  115. package/skills/manage-problem/test/manage-problem-transitive-dependencies.bats +0 -365
  116. package/skills/manage-problem/test/manage-problem-verification-detection.bats +0 -64
  117. package/skills/manage-problem/test/manage-problem-verification-pending.bats +0 -114
  118. package/skills/manage-problem/test/manage-problem-work-forwarder.bats +0 -88
  119. package/skills/manage-story/test/manage-story-contract.bats +0 -174
  120. package/skills/manage-story-map/test/manage-story-map-contract.bats +0 -63
  121. package/skills/mitigate-incident/test/mitigate-incident-contract.bats +0 -258
  122. package/skills/reconcile-readme/test/reconcile-readme-contract.bats +0 -201
  123. package/skills/report-upstream/test/report-upstream-contract.bats +0 -394
  124. package/skills/restore-incident/test/restore-incident-contract.bats +0 -170
  125. package/skills/review-problems/test/inbound-channels-cache-shape.bats +0 -127
  126. package/skills/review-problems/test/inbound-discovery-contract.bats +0 -383
  127. package/skills/review-problems/test/jtbd-301-verdict-shape-contract.bats +0 -225
  128. package/skills/review-problems/test/review-problems-contract.bats +0 -235
  129. package/skills/review-problems/test/review-problems-likely-verified-cell-shape.bats +0 -229
  130. package/skills/scaffold-intake/test/scaffold-intake-contract.bats +0 -126
  131. package/skills/scaffold-intake/test/scaffold-intake-fixture.bats +0 -164
  132. package/skills/scaffold-intake/test/scaffold-intake-secrets-absent.bats +0 -87
  133. package/skills/transition-problem/test/transition-problem-contract.bats +0 -285
  134. package/skills/transition-problems/test/transition-problems-contract.bats +0 -331
  135. package/skills/update-upstream/test/update-upstream-contract.bats +0 -375
  136. package/skills/work-problem/test/work-problem-contract.bats +0 -294
  137. package/skills/work-problems/test/work-problems-above-appetite-remediation.bats +0 -139
  138. package/skills/work-problems/test/work-problems-adr-013-rule-6-p352-amendment.bats +0 -166
  139. package/skills/work-problems/test/work-problems-auto-migrate-step.bats +0 -57
  140. package/skills/work-problems/test/work-problems-cost-logging.bats +0 -109
  141. package/skills/work-problems/test/work-problems-deviation-candidate-shape.bats +0 -121
  142. package/skills/work-problems/test/work-problems-first-run-intake-prompt.bats +0 -36
  143. package/skills/work-problems/test/work-problems-inter-iteration-verify.bats +0 -59
  144. package/skills/work-problems/test/work-problems-mid-loop-userpromptsubmit-handler.bats +0 -69
  145. package/skills/work-problems/test/work-problems-no-mid-loop-asking.bats +0 -192
  146. package/skills/work-problems/test/work-problems-p341-pre-all-done-gate.bats +0 -122
  147. package/skills/work-problems/test/work-problems-p342-r007-derive-then-pass-flags.bats +0 -170
  148. package/skills/work-problems/test/work-problems-p342-retro-auto-ticket-carveout.bats +0 -120
  149. package/skills/work-problems/test/work-problems-preflight-failure-handling.bats +0 -248
  150. package/skills/work-problems/test/work-problems-preflight-session-continuity.bats +0 -139
  151. package/skills/work-problems/test/work-problems-preflight.bats +0 -69
  152. package/skills/work-problems/test/work-problems-release-cadence.bats +0 -63
  153. package/skills/work-problems/test/work-problems-step-0-iter-error-staleness.bats +0 -93
  154. package/skills/work-problems/test/work-problems-step-0b-cache-staleness-behavioural.bats +0 -138
  155. package/skills/work-problems/test/work-problems-step-0c-deferred-placeholder-staleness-behavioural.bats +0 -238
  156. package/skills/work-problems/test/work-problems-step-0d-outbound-responses-staleness-behavioural.bats +0 -174
  157. package/skills/work-problems/test/work-problems-step-2-5-routing.bats +0 -80
  158. package/skills/work-problems/test/work-problems-step-2-5b-cross-halt-routing.bats +0 -149
  159. package/skills/work-problems/test/work-problems-step-3-5-jtbd-ratification-predicate.bats +0 -191
  160. package/skills/work-problems/test/work-problems-step-5-bats-polling-discipline.bats +0 -91
  161. package/skills/work-problems/test/work-problems-step-5-delegation.bats +0 -333
  162. package/skills/work-problems/test/work-problems-step-5-idle-timeout-sigterm.bats +0 -421
  163. package/skills/work-problems/test/work-problems-step-5-is-error-transient-halt.bats +0 -278
  164. package/skills/work-problems/test/work-problems-step-5-iter-changeset-required.bats +0 -95
  165. package/skills/work-problems/test/work-problems-step-5-prompt-body-re-grounding.bats +0 -128
  166. package/skills/work-problems/test/work-problems-step-5-stream-timeout-salvage.bats +0 -251
  167. package/skills/work-problems/test/work-problems-step-6-5-always-drain.bats +0 -203
  168. package/skills/work-problems/test/work-problems-step-6-5-cache-refresh-chain.bats +0 -174
  169. package/skills/work-problems/test/work-problems-step-6-5-fix-and-continue.bats +0 -254
  170. package/skills/work-problems/test/work-problems-step-6-5-postrelease-kv-callback.bats +0 -209
  171. package/skills/work-problems/test/work-problems-stop-condition-questions.bats +0 -85
@@ -1,317 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Behavioural fixtures for /wr-itil:capture-story (P170 Phase 2 Slice 7).
3
- #
4
- # Per ADR-052 (Behavioural-tests-default for skill testing), these tests
5
- # exercise the load-bearing primitives the skill dispatches and assert
6
- # observable state — NOT the prose contents of SKILL.md.
7
- #
8
- # Behavioural surfaces under test:
9
- # 1. Next-ID computation — capture-story uses the inline
10
- # max(local, origin) + 1 formula scanning docs/stories/*/STORY-*.md
11
- # + git ls-tree -r origin/main docs/stories/ per ADR-019 inline
12
- # collision-guard approved at Slice 3 design review (option a).
13
- # 2. ID collision-on-origin renumber — when an origin RFC IS not yet
14
- # pulled locally, the formula must compute the higher of the two
15
- # and increment from there (no silent collision).
16
- # 3. Reverse-trace helper "Stories" section-name support — the three
17
- # Slice 2a/2b helpers (update-problem / update-jtbd / update-rfc
18
- # -references-section.sh) must accept "Stories" as a section name.
19
- # 4. Frontmatter shape — a captured story file conforms to ADR-060
20
- # lines 220-228 (status: draft / story-id / problems / jtbd / etc.).
21
- # 5. NO update-story-references-section.sh "Stories" path —
22
- # story-maps are HTML; the story-tier reverse-trace helper does NOT
23
- # accept "Stories" (per architect amend finding 2 on Slice 7).
24
- #
25
- # @problem P170
26
- # @jtbd JTBD-008 (Decompose a Fix Into Coordinated Changes — capture-time
27
- # decomposition surface)
28
- # @jtbd JTBD-001 (extended scope — change-set-level governance)
29
- # @adr ADR-060 (Problem-RFC-Story framework — story tier)
30
- # @adr ADR-052 (Behavioural-tests-default)
31
- # @adr ADR-019 (ID collision-on-origin renumber)
32
- # @adr ADR-014 (single-commit grain)
33
-
34
- setup() {
35
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
36
- SKILL_FILE="${REPO_ROOT}/packages/itil/skills/capture-story/SKILL.md"
37
- HELPER_PROBLEM="${REPO_ROOT}/packages/itil/scripts/update-problem-references-section.sh"
38
- HELPER_JTBD="${REPO_ROOT}/packages/itil/scripts/update-jtbd-references-section.sh"
39
- HELPER_RFC="${REPO_ROOT}/packages/itil/scripts/update-rfc-references-section.sh"
40
- HELPER_STORY="${REPO_ROOT}/packages/itil/scripts/update-story-references-section.sh"
41
-
42
- TMPROOT=$(mktemp -d)
43
- ORIG_DIR="$PWD"
44
- cd "$TMPROOT"
45
- }
46
-
47
- teardown() {
48
- cd "$ORIG_DIR"
49
- rm -rf "$TMPROOT"
50
- }
51
-
52
- # ---------------------------------------------------------------------------
53
- # Surface 0: SKILL.md exists with correct name (minimum discoverability)
54
- # ---------------------------------------------------------------------------
55
-
56
- @test "capture-story: SKILL.md exists" {
57
- [ -f "$SKILL_FILE" ]
58
- }
59
-
60
- @test "capture-story: SKILL.md frontmatter declares wr-itil:capture-story name" {
61
- # Discoverable on / autocomplete depends on the canonical name.
62
- run grep -E '^name: wr-itil:capture-story$' "$SKILL_FILE"
63
- [ "$status" -eq 0 ]
64
- }
65
-
66
- # ---------------------------------------------------------------------------
67
- # Surface 1: Next-ID computation — inline formula matches capture-rfc precedent
68
- # (verified against a fixture stories directory).
69
- # ---------------------------------------------------------------------------
70
-
71
- @test "capture-story: next-ID formula computes 001 for empty stories directory" {
72
- mkdir -p docs/stories/draft
73
- local_max=$(ls docs/stories/*/STORY-*.md 2>/dev/null | sed 's|.*/STORY-||;s|-.*||' | grep -oE '^[0-9]+' | sort -n | tail -1)
74
- origin_max="" # no git fixture; treat as empty
75
- next=$(printf '%03d' $(( 10#$(echo -e "${local_max:-0}\n${origin_max:-0}" | sort -n | tail -1) + 1 )))
76
- [ "$next" = "001" ]
77
- }
78
-
79
- @test "capture-story: next-ID formula computes 003 when STORY-002 exists locally" {
80
- mkdir -p docs/stories/draft docs/stories/in-progress
81
- touch docs/stories/draft/STORY-002-foo.md
82
- touch docs/stories/in-progress/STORY-001-bar.md
83
- local_max=$(ls docs/stories/*/STORY-*.md 2>/dev/null | sed 's|.*/STORY-||;s|-.*||' | grep -oE '^[0-9]+' | sort -n | tail -1)
84
- next=$(printf '%03d' $(( 10#${local_max:-0} + 1 )))
85
- [ "$next" = "003" ]
86
- }
87
-
88
- @test "capture-story: next-ID formula picks max(local, origin) when origin is higher (collision-on-origin renumber)" {
89
- # Simulates the renumber: local has STORY-002, origin has STORY-005.
90
- # Formula must pick 005 + 1 = 006, not 002 + 1 = 003 (silent collision).
91
- local_max=2
92
- origin_max=5
93
- next=$(printf '%03d' $(( 10#$(echo -e "${local_max:-0}\n${origin_max:-0}" | sort -n | tail -1) + 1 )))
94
- [ "$next" = "006" ]
95
- }
96
-
97
- @test "capture-story: next-ID formula picks max(local, origin) when local is higher" {
98
- # Reverse case: local STORY-007, origin STORY-003. Local wins → 008.
99
- local_max=7
100
- origin_max=3
101
- next=$(printf '%03d' $(( 10#$(echo -e "${local_max:-0}\n${origin_max:-0}" | sort -n | tail -1) + 1 )))
102
- [ "$next" = "008" ]
103
- }
104
-
105
- # ---------------------------------------------------------------------------
106
- # Surface 2: Reverse-trace helpers accept "Stories" section name
107
- # (Slice 2a/2b shipped these — verify they're still wired correctly).
108
- # ---------------------------------------------------------------------------
109
-
110
- @test "capture-story: update-problem-references-section.sh accepts 'Stories' section name without rejecting" {
111
- # Set up minimal fixture: a problem file with a Story Maps placeholder
112
- # section. The helper should accept "Stories" as a valid lookup key
113
- # (architect finding on Slice 7: the absence of Stories support here
114
- # would block the inline reverse-trace refresh in capture-story Step 6).
115
- mkdir -p docs/problems/known-error docs/stories/draft
116
- cat > docs/problems/known-error/170-test-problem.md <<EOF
117
- # P170: Test problem
118
-
119
- ## Story Maps
120
-
121
- (empty)
122
-
123
- ## Stories
124
-
125
- (empty)
126
- EOF
127
- run bash "$HELPER_PROBLEM" docs/problems/known-error/170-test-problem.md Stories
128
- # Acceptable outcomes: success (0) or no-op-with-stderr; rejection (e.g.
129
- # "unknown section-name") would fail this assertion.
130
- [[ "$output" != *"unknown section-name"* ]]
131
- }
132
-
133
- @test "capture-story: update-jtbd-references-section.sh accepts 'Stories' section name" {
134
- mkdir -p docs/jtbd/solo-developer docs/stories/draft
135
- cat > docs/jtbd/solo-developer/JTBD-008-test.proposed.md <<EOF
136
- # JTBD-008: Test
137
-
138
- ## Stories
139
-
140
- (empty)
141
- EOF
142
- run bash "$HELPER_JTBD" docs/jtbd/solo-developer/JTBD-008-test.proposed.md Stories
143
- [[ "$output" != *"unknown section-name"* ]]
144
- }
145
-
146
- @test "capture-story: update-rfc-references-section.sh accepts 'Stories' section name" {
147
- mkdir -p docs/rfcs docs/stories/draft
148
- cat > docs/rfcs/RFC-002-test.verifying.md <<EOF
149
- # RFC-002: Test
150
-
151
- ## Stories
152
-
153
- (empty)
154
- EOF
155
- run bash "$HELPER_RFC" docs/rfcs/RFC-002-test.verifying.md Stories
156
- [[ "$output" != *"unknown section-name"* ]]
157
- }
158
-
159
- # ---------------------------------------------------------------------------
160
- # Surface 3: NO update-story-references-section.sh "Stories" path
161
- # (architect amend finding 2 on Slice 7 — story-maps are HTML, no markdown
162
- # reverse-trace section auto-maintained on the HTML map; capture-story does
163
- # NOT stage story-map files.)
164
- # ---------------------------------------------------------------------------
165
-
166
- @test "capture-story: update-story-references-section.sh does NOT accept 'Stories' section name (architect finding 2 — story-maps are HTML, manually authored)" {
167
- mkdir -p docs/stories/draft
168
- cat > docs/stories/draft/STORY-001-test.md <<EOF
169
- # STORY-001: Test
170
- EOF
171
- run bash "$HELPER_STORY" docs/stories/draft/STORY-001-test.md Stories
172
- # The helper's lookup table supports RFCs + Story Maps but NOT Stories
173
- # (per architect finding 2). The helper MUST exit non-zero AND name
174
- # the supported sections in its error stream.
175
- [ "$status" -ne 0 ]
176
- [[ "$output" == *"unknown section-name"* ]] || [[ "$output" == *"Supported"* ]]
177
- }
178
-
179
- # ---------------------------------------------------------------------------
180
- # Surface 4: Frontmatter shape — verify ADR-060 lines 220-228 fields
181
- # round-trip through a minimal capture sequence.
182
- # ---------------------------------------------------------------------------
183
-
184
- @test "capture-story: captured frontmatter contains required fields per ADR-060 lines 220-228" {
185
- # Construct the frontmatter the way the skill prescribes (Step 5).
186
- mkdir -p docs/stories/draft
187
- next_id="001"
188
- slug="test-capture"
189
- description="Test capture"
190
- reported=$(date -u +%Y-%m-%d)
191
- cat > "docs/stories/draft/STORY-${next_id}-${slug}.md" <<EOF
192
- ---
193
- status: draft
194
- story-id: ${slug}
195
- reported: ${reported}
196
- decision-makers: [Test]
197
- problems: [P170]
198
- jtbd: [JTBD-008]
199
- rfcs: []
200
- story-maps: [STORY-MAP-001]
201
- estimated-effort: M
202
- ---
203
-
204
- # STORY-${next_id}: ${description}
205
- EOF
206
- # Assert each required frontmatter field appears (grep is sufficient —
207
- # ADR-052 prefers behavioural assertion on the observable file state).
208
- story_file="docs/stories/draft/STORY-${next_id}-${slug}.md"
209
- for field in status story-id reported decision-makers problems jtbd rfcs story-maps estimated-effort; do
210
- run grep -E "^${field}:" "$story_file"
211
- [ "$status" -eq 0 ]
212
- done
213
- }
214
-
215
- @test "capture-story: I8-at-capture invariant — a valid captured story has a NON-EMPTY story-maps: (ADR-095)" {
216
- mkdir -p docs/stories/draft
217
- cat > docs/stories/draft/STORY-001-mapped.md <<EOF
218
- ---
219
- status: draft
220
- story-maps: [STORY-MAP-002]
221
- ---
222
- EOF
223
- run grep -E '^story-maps: \[STORY-MAP-[0-9]' docs/stories/draft/STORY-001-mapped.md
224
- [ "$status" -eq 0 ]
225
- run grep -E '^story-maps: \[\]' docs/stories/draft/STORY-001-mapped.md
226
- [ "$status" -ne 0 ]
227
- }
228
-
229
- @test "capture-story: SKILL prescribes refuse-and-route on a missing story-map trace (I8/ADR-095)" {
230
- run grep -E 'I8 hard-block AT CAPTURE|refuse-and-route|missing-story-map-trace' "$SKILL_FILE"
231
- [ "$status" -eq 0 ]
232
- run grep -E 'story-map traces are optional at capture' "$SKILL_FILE"
233
- [ "$status" -ne 0 ]
234
- }
235
-
236
- @test "capture-story: captured story file lands at docs/stories/draft/ per ADR-060 lines 145-147" {
237
- # Story-maps use HTML and lifecycle subdirs (draft/accepted/in-progress/
238
- # completed/archived); stories use markdown and lifecycle subdirs
239
- # (draft/accepted/in-progress/done/archived). Captured story lands at
240
- # draft/ per the skill's Step 5 prescription.
241
- mkdir -p docs/stories/draft
242
- touch docs/stories/draft/STORY-001-test.md
243
- [ -f docs/stories/draft/STORY-001-test.md ]
244
- # Negative assertion: NOT in any other subdir at capture time.
245
- [ ! -f docs/stories/accepted/STORY-001-test.md ]
246
- [ ! -f docs/stories/in-progress/STORY-001-test.md ]
247
- [ ! -f docs/stories/done/STORY-001-test.md ]
248
- }
249
-
250
- # --- P474 / STORY-054: the lifecycle mirror must stay gone ---------------------
251
- # A `**Status**:` body line duplicating the frontmatter `status:` used to sit in
252
- # this template. The oversight fingerprint excludes the frontmatter key but
253
- # hashed the body copy, so advancing a story un-ratified it and the no-implement
254
- # gate then denied its own implementing commit. This was the FOURTH such
255
- # lifecycle mirror in a family of three, so the removal needs a lock: without
256
- # one, the next template edit reintroduces it and nothing fails.
257
-
258
- @test "P474: the capture-story template emits no **Status** body mirror" {
259
- # Behavioural on the artefact the skill prescribes, not on prose ABOUT it:
260
- # extract the template's own story scaffold and assert the shape it produces.
261
- # The SKILL may still MENTION the forbidden line in its do-not-reintroduce
262
- # note, so match only a line-start emission inside a fenced block.
263
- run bash -c "awk '/^# STORY-<NNN>/,/^## Dependencies/' '$SKILL_FILE' | grep -cE '^\*\*Status\*\*:'"
264
- [ "$output" = "0" ]
265
- # Anti-vacuity: if a heading rename ever empties the awk range, the grep -c
266
- # above returns 0 and passes while the mirror is present. Assert the range
267
- # actually contains the sibling field that DID survive.
268
- run bash -c "awk '/^# STORY-<NNN>/,/^## Dependencies/' '$SKILL_FILE' | grep -cE '^\*\*Reported\*\*:'"
269
- [ "$output" -ge 1 ]
270
- }
271
-
272
- @test "P474: the documented story body shape emits no **Status** body mirror" {
273
- # The second carrier. docs/stories/README.md is the ADOPTER-facing one —
274
- # reconcile-stories.sh reads the adopter's own copy — so a stale shape here
275
- # has them hand-author the mirror straight back in.
276
- local readme="${REPO_ROOT}/docs/stories/README.md"
277
- [ -f "$readme" ]
278
- run bash -c "awk '/^# STORY-<NNN>/,/^## /' '$readme' | grep -cE '^\*\*Status\*\*:'"
279
- [ "$output" = "0" ]
280
- # Same anti-vacuity guard as the template carrier above.
281
- run bash -c "awk '/^# STORY-<NNN>/,/^## /' '$readme' | grep -cE '^\*\*Reported\*\*:'"
282
- [ "$output" -ge 1 ]
283
- }
284
-
285
- @test "P474: a template-shaped story keeps its ratification across an accept transition" {
286
- # The invariant the prose serves. Seeds a story in the shape the template now
287
- # produces, ratifies it, advances status + ticks a criterion, and asserts the
288
- # fingerprint still matches — the exact sequence that used to drift.
289
- # shellcheck source=/dev/null
290
- source "${REPO_ROOT}/packages/itil/lib/story-oversight.sh"
291
- mkdir -p docs/stories/draft
292
- local f=docs/stories/draft/STORY-902-shape.md
293
- printf -- '---\nstatus: draft\nstory-id: shape\nhuman-oversight: confirmed\noversight-hash: P\n---\n\n# STORY-902: a story\n\n**Reported**: 2026-07-30\n\n## User value\n\nvalue.\n\n## Acceptance criteria\n\n- [ ] a criterion\n' > "$f"
294
- local h; h="$(oversight_content_hash "$f")"
295
- sed -i.bak "s/oversight-hash: P/oversight-hash: $h/" "$f" && rm -f "$f.bak"
296
- run is_story_map_ratified "$f"
297
- [ "$status" -eq 0 ]
298
-
299
- sed -i.bak 's/^status: draft/status: accepted/; s/- \[ \] a criterion/- [x] a criterion/' "$f" && rm -f "$f.bak"
300
- run is_story_map_ratified "$f"
301
- [ "$status" -eq 0 ]
302
- }
303
-
304
- @test "P474: reintroducing the mirror DOES drift a ratified story (the lock has teeth)" {
305
- # Proves the invariant test above is not vacuous: put the mirror back and the
306
- # accept transition drifts again, which is the defect.
307
- # shellcheck source=/dev/null
308
- source "${REPO_ROOT}/packages/itil/lib/story-oversight.sh"
309
- mkdir -p docs/stories/draft
310
- local f=docs/stories/draft/STORY-903-regress.md
311
- printf -- '---\nstatus: draft\nstory-id: regress\nhuman-oversight: confirmed\noversight-hash: P\n---\n\n# STORY-903: a story\n\n**Status**: draft\n**Reported**: 2026-07-30\n\n## User value\n\nvalue.\n' > "$f"
312
- local h; h="$(oversight_content_hash "$f")"
313
- sed -i.bak "s/oversight-hash: P/oversight-hash: $h/" "$f" && rm -f "$f.bak"
314
- sed -i.bak 's/^status: draft/status: accepted/; s/^\*\*Status\*\*: draft/**Status**: accepted/' "$f" && rm -f "$f.bak"
315
- run is_story_map_ratified "$f"
316
- [ "$status" -ne 0 ]
317
- }
@@ -1,98 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Behavioural fixtures for /wr-itil:capture-story-map (P170 Phase 2 Slice 3 — ADR-060).
3
- #
4
- # Mirrors capture-story-behavioural.bats with story-map-tier adjustments
5
- # (HTML encoding, I3 + I4 invariants instead of I6 + I9, no optional
6
- # --rfc / --story-map flags).
7
-
8
- setup() {
9
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
10
- SKILL_FILE="${REPO_ROOT}/packages/itil/skills/capture-story-map/SKILL.md"
11
- HELPER_PROBLEM="${REPO_ROOT}/packages/itil/scripts/update-problem-references-section.sh"
12
- HELPER_JTBD="${REPO_ROOT}/packages/itil/scripts/update-jtbd-references-section.sh"
13
-
14
- TMPROOT=$(mktemp -d)
15
- ORIG_DIR="$PWD"
16
- cd "$TMPROOT"
17
- }
18
-
19
- teardown() {
20
- cd "$ORIG_DIR"
21
- rm -rf "$TMPROOT"
22
- }
23
-
24
- @test "capture-story-map: SKILL.md exists" {
25
- [ -f "$SKILL_FILE" ]
26
- }
27
-
28
- @test "capture-story-map: SKILL.md frontmatter declares wr-itil:capture-story-map name" {
29
- run grep -E '^name: wr-itil:capture-story-map$' "$SKILL_FILE"
30
- [ "$status" -eq 0 ]
31
- }
32
-
33
- @test "capture-story-map: SKILL.md names I3 trace-to-problem invariant" {
34
- run grep -E 'I3 hard-block|I3.*trace-to-problem' "$SKILL_FILE"
35
- [ "$status" -eq 0 ]
36
- }
37
-
38
- @test "capture-story-map: SKILL.md names I4 trace-to-JTBD invariant" {
39
- run grep -E 'I4 hard-block|I4.*trace-to-JTBD' "$SKILL_FILE"
40
- [ "$status" -eq 0 ]
41
- }
42
-
43
- @test "capture-story-map: next-ID formula computes 001 for empty story-maps directory" {
44
- mkdir -p docs/story-maps/draft
45
- local_max=$(ls docs/story-maps/*/STORY-MAP-*.html 2>/dev/null | sed 's|.*/STORY-MAP-||;s|-.*||' | grep -oE '^[0-9]+' | sort -n | tail -1)
46
- next=$(printf '%03d' $(( 10#${local_max:-0} + 1 )))
47
- [ "$next" = "001" ]
48
- }
49
-
50
- @test "capture-story-map: next-ID formula computes 003 when STORY-MAP-002 exists locally" {
51
- mkdir -p docs/story-maps/draft docs/story-maps/in-progress
52
- touch docs/story-maps/draft/STORY-MAP-002-foo.html
53
- touch docs/story-maps/in-progress/STORY-MAP-001-bar.html
54
- local_max=$(ls docs/story-maps/*/STORY-MAP-*.html 2>/dev/null | sed 's|.*/STORY-MAP-||;s|-.*||' | grep -oE '^[0-9]+' | sort -n | tail -1)
55
- next=$(printf '%03d' $(( 10#${local_max:-0} + 1 )))
56
- [ "$next" = "003" ]
57
- }
58
-
59
- @test "capture-story-map: update-problem-references-section.sh accepts 'Story Maps' section name" {
60
- mkdir -p docs/problems/known-error docs/story-maps/draft
61
- cat > docs/problems/known-error/170-test.md <<'EOF'
62
- # P170: Test
63
-
64
- ## Story Maps
65
-
66
- (empty)
67
- EOF
68
- run bash "$HELPER_PROBLEM" docs/problems/known-error/170-test.md "Story Maps"
69
- [[ "$output" != *"unknown section-name"* ]]
70
- }
71
-
72
- @test "capture-story-map: update-jtbd-references-section.sh accepts 'Story Maps' section name" {
73
- mkdir -p docs/jtbd/solo-developer docs/story-maps/draft
74
- cat > docs/jtbd/solo-developer/JTBD-008-test.proposed.md <<'EOF'
75
- # JTBD-008: Test
76
-
77
- ## Story Maps
78
-
79
- (empty)
80
- EOF
81
- run bash "$HELPER_JTBD" docs/jtbd/solo-developer/JTBD-008-test.proposed.md "Story Maps"
82
- [[ "$output" != *"unknown section-name"* ]]
83
- }
84
-
85
- @test "capture-story-map: SKILL.md prescribes HTML encoding per ADR-060 amendment 2026-05-12" {
86
- run grep -E 'HTML5|<!DOCTYPE html>|encoding amendment 2026-05-12' "$SKILL_FILE"
87
- [ "$status" -eq 0 ]
88
- }
89
-
90
- @test "capture-story-map: SKILL.md prescribes draft/ landing subdir" {
91
- run grep -E 'docs/story-maps/draft/STORY-MAP' "$SKILL_FILE"
92
- [ "$status" -eq 0 ]
93
- }
94
-
95
- @test "capture-story-map: SKILL.md prohibits inline style on data-bearing elements per STYLE-GUIDE.md" {
96
- run grep -iE 'NO inline.*style.*data-bearing|prohibited inline.*style' "$SKILL_FILE"
97
- [ "$status" -eq 0 ]
98
- }
@@ -1,146 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Contract assertions for /wr-itil:close-incident (P071 split slice 6c).
3
- #
4
- # This skill hosts the "close a restored incident" user intent previously
5
- # hidden behind /wr-itil:manage-incident <I> close. It checks the Linked
6
- # Problem's file suffix and, if the problem is in an acceptable terminal
7
- # state (.known-error.md / .verifying.md / .closed.md) OR the incident
8
- # documents a No Problem justification, renames the incident file from
9
- # .restored.md to .closed.md and updates the Status field.
10
- #
11
- # Structural assertion — Permitted Exception to the source-grep ban
12
- # (ADR-005 / P011 / ADR-037 contract-assertion pattern).
13
- #
14
- # @problem P071
15
- # @jtbd JTBD-001 (enforce governance without slowing down — discoverable surface)
16
- # @jtbd JTBD-101 (extend the suite with clear patterns — one skill per distinct user intent)
17
- # @jtbd JTBD-201 (restore service fast with an audit trail — close gate preserves the problem-handoff link)
18
- #
19
- # Cross-reference:
20
- # P071: docs/problems/071-argument-based-skill-subcommands-are-not-discoverable.open.md
21
- # ADR-010 amended (Skill Granularity section) — split naming + forwarder contract
22
- # ADR-011 — manage-incident skill-wrapping precedent (close gate on linked problem)
23
- # ADR-022 — problem lifecycle verification-pending status (.verifying.md accepted alongside .known-error.md / .closed.md)
24
- # ADR-037 — contract-assertion bats pattern
25
-
26
- setup() {
27
- SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
28
- SKILL_FILE="${SKILL_DIR}/SKILL.md"
29
- }
30
-
31
- @test "SKILL.md exists and has frontmatter" {
32
- [ -f "$SKILL_FILE" ]
33
- run head -1 "$SKILL_FILE"
34
- [ "$status" -eq 0 ]
35
- [ "$output" = "---" ]
36
- }
37
-
38
- @test "SKILL.md frontmatter name is wr-itil:close-incident (P071 + ADR-010 amended)" {
39
- # Split naming convention per ADR-010 amendment: <verb>-<object> pair.
40
- # The new skill's name must match the phased-landing plan pinned in P071.
41
- run grep -n "^name: wr-itil:close-incident$" "$SKILL_FILE"
42
- [ "$status" -eq 0 ]
43
- }
44
-
45
- @test "SKILL.md frontmatter description names the close intent (P071)" {
46
- # Description must name "close" and "incident" so Claude Code autocomplete
47
- # surfaces the user intent rather than a generic name.
48
- run grep -inE "^description:.*clos.*incident|^description:.*incident.*clos" "$SKILL_FILE"
49
- [ "$status" -eq 0 ]
50
- }
51
-
52
- @test "SKILL.md frontmatter allowed-tools grants file-mutation surface (P071 — close requires rename + edit)" {
53
- # close-incident renames .restored.md → .closed.md and updates the
54
- # Status field. Unlike restore-incident, the linked-problem gate is a
55
- # hard check (not a prompt), so no AskUserQuestion is required. No
56
- # cross-skill invocation either, so no Skill tool is required.
57
- run grep -nE "^allowed-tools:" "$SKILL_FILE"
58
- [ "$status" -eq 0 ]
59
- run grep -nE "^allowed-tools:.*Write" "$SKILL_FILE"
60
- [ "$status" -eq 0 ]
61
- run grep -nE "^allowed-tools:.*Edit" "$SKILL_FILE"
62
- [ "$status" -eq 0 ]
63
- run grep -nE "^allowed-tools:.*Bash" "$SKILL_FILE"
64
- [ "$status" -eq 0 ]
65
- }
66
-
67
- @test "SKILL.md documents the .restored.md → .closed.md rename (P071 + ADR-011)" {
68
- # The close transition renames the incident file from .restored.md
69
- # to .closed.md. The SKILL.md must name both suffixes explicitly so
70
- # the file-suffix contract is legible.
71
- run grep -inE "\.restored\.md" "$SKILL_FILE"
72
- [ "$status" -eq 0 ]
73
- run grep -inE "\.closed\.md" "$SKILL_FILE"
74
- [ "$status" -eq 0 ]
75
- }
76
-
77
- @test "SKILL.md documents the Linked-Problem gate with .known-error.md allowance (P071 + ADR-011)" {
78
- # Per ADR-011, the close gate accepts a linked problem in
79
- # .known-error.md state. Older form of the gate — must still be
80
- # named explicitly post-ADR-022.
81
- run grep -inE "known-error" "$SKILL_FILE"
82
- [ "$status" -eq 0 ]
83
- }
84
-
85
- @test "SKILL.md documents the Linked-Problem gate .verifying.md allowance (P071 + ADR-022)" {
86
- # Per ADR-022, .verifying.md (fix released, root cause confirmed,
87
- # awaiting verification) also satisfies the incident-close gate.
88
- # The SKILL.md must name this allowance explicitly so the ADR-022
89
- # extension is preserved post-split.
90
- run grep -inE "\.verifying\.md|verifying" "$SKILL_FILE"
91
- [ "$status" -eq 0 ]
92
- }
93
-
94
- @test "SKILL.md documents the No Problem justification path (P071 + ADR-011)" {
95
- # Per ADR-011, the incident may carry a ## No Problem section with a
96
- # justification (e.g. "one-off cosmic-bit-flip"). In that case the
97
- # linked-problem gate is bypassed. The SKILL.md must document the
98
- # No Problem acceptance so the audit trail invariant is preserved.
99
- run grep -inE "No Problem|no problem" "$SKILL_FILE"
100
- [ "$status" -eq 0 ]
101
- }
102
-
103
- @test "SKILL.md documents the .open.md block condition (P071 + ADR-011)" {
104
- # Per ADR-011, a linked problem in .open.md state blocks the close.
105
- # The user must transition the problem to Known Error (or the
106
- # verification pipeline must complete) before the incident can close.
107
- # The SKILL.md must name this blocking condition explicitly.
108
- run grep -inE "\.open\.md|Open" "$SKILL_FILE"
109
- [ "$status" -eq 0 ]
110
- }
111
-
112
- @test "SKILL.md cites P071 and ADR-010 amended (P071 + ADR-025)" {
113
- # ADR-025 inheritance per ADR-037: contract-assertion bats should reflect
114
- # traceability cites on the skill spec document.
115
- run grep -inE "P071|ADR-010" "$SKILL_FILE"
116
- [ "$status" -eq 0 ]
117
- }
118
-
119
- @test "SKILL.md cites ADR-011 + ADR-022 for the close gate (P071 + ADR-011 + ADR-022)" {
120
- # close-incident inherits the Linked-Problem gate from ADR-011 and the
121
- # .verifying.md extension from ADR-022. Both must be cited so the
122
- # precedent chain is legible.
123
- run grep -inE "ADR-011" "$SKILL_FILE"
124
- [ "$status" -eq 0 ]
125
- run grep -inE "ADR-022" "$SKILL_FILE"
126
- [ "$status" -eq 0 ]
127
- }
128
-
129
- @test "SKILL.md does not carry a deprecated-arguments frontmatter flag (clean-split skill)" {
130
- # close-incident is a clean-split skill with no argument-subcommands
131
- # itself (its argument is a data parameter — incident ID only).
132
- # ADR-010 amendment's `deprecated-arguments: true` flag is only valid
133
- # on host skills with forwarder routes. close-incident is a
134
- # forwarder TARGET, not a host. It must NOT carry the flag.
135
- run grep -E "^deprecated-arguments:" "$SKILL_FILE"
136
- [ "$status" -ne 0 ]
137
- }
138
-
139
- @test "SKILL.md does not use word-argument subcommand branching (P071 regression guard)" {
140
- # The whole point of P071: Claude Code autocomplete does not surface
141
- # word-argument subcommands. A clean-split skill must not reintroduce
142
- # word-arg subcommand routing. The data parameter <I> is a string,
143
- # not a verb keyword.
144
- run grep -inE "If arguments start with \"(list|mitigate|restore|close|link)\"|If arguments contain \"(list|mitigate|restore|close|link)\"" "$SKILL_FILE"
145
- [ "$status" -ne 0 ]
146
- }