@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,220 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # P132 Phase 2b: itil-mid-loop-ask-detect.sh Stop hook detects
4
- # orchestrator main-turn AskUserQuestion calls fired mid-loop inside
5
- # /wr-itil:work-problems — the regression class P132 captures
6
- # (2026-05-17 reopen: orchestrator asked iter-target selection between
7
- # iters 3 and 4; halted the loop for hours of AFK time).
8
- #
9
- # Detection signal:
10
- # 1. Last assistant turn contains an AskUserQuestion tool_use
11
- # 2. Earlier transcript contains a Skill tool_use to wr-itil:work-problems
12
- # 3. No `ALL_DONE` / `## Work Problems Summary` marker has been emitted
13
- # since the skill activation (mid-loop, not post-loop wrap)
14
- #
15
- # When all three match the hook emits a structured `stopReason`
16
- # advisory citing P130 + the Mid-loop ask discipline subsection of
17
- # work-problems SKILL.md. Advisory only — never blocks. Mirrors the
18
- # itil-assistant-output-review.sh Stop hook precedent (P085 prose-ask
19
- # detection) but on a different signal class.
20
- #
21
- # Per ADR-005 / ADR-052 — bats live under packages/<plugin>/hooks/test/
22
- # and assert behaviour on emitted JSON, not source-content. Per
23
- # feedback_behavioural_tests.md (P081) — no source-grep on hook text.
24
-
25
- setup() {
26
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
27
- HOOK="$REPO_ROOT/packages/itil/hooks/itil-mid-loop-ask-detect.sh"
28
- TMPDIR_="$(mktemp -d)"
29
- TRANSCRIPT="$TMPDIR_/transcript.jsonl"
30
- }
31
-
32
- teardown() {
33
- rm -rf "$TMPDIR_"
34
- }
35
-
36
- # Helper: emit the JSONL transcript line for an assistant turn
37
- # containing a Skill tool_use to wr-itil:work-problems.
38
- emit_orchestrator_activation() {
39
- cat <<'JSON'
40
- {"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Skill","input":{"skill":"wr-itil:work-problems"}}]}}
41
- JSON
42
- }
43
-
44
- # Helper: emit a benign assistant text turn (no tool_use).
45
- emit_text_turn() {
46
- local text="$1"
47
- printf '{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":%s}]}}\n' \
48
- "$(printf '%s' "$text" | jq -Rs .)"
49
- }
50
-
51
- # Helper: emit an assistant turn containing an AskUserQuestion tool_use.
52
- emit_ask_turn() {
53
- local header="${1:-Next problem}"
54
- cat <<JSON
55
- {"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"AskUserQuestion","input":{"questions":[{"question":"Pick next iter","header":"${header}","options":[{"label":"A","description":"x"},{"label":"B","description":"y"}]}]}}]}}
56
- JSON
57
- }
58
-
59
- run_hook() {
60
- echo "{\"session_id\":\"mid-loop-test\",\"transcript_path\":$(printf '%s' "$TRANSCRIPT" | jq -Rs .)}" | bash "$HOOK"
61
- }
62
-
63
- # --- Positive detection ---
64
-
65
- @test "detect: orchestrator activation + final AskUserQuestion + no terminal marker emits stopReason" {
66
- {
67
- printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
68
- emit_orchestrator_activation
69
- emit_text_turn "Iter 1 complete. Dispatching iter 2."
70
- emit_text_turn "Iter 2 complete. Dispatching iter 3."
71
- emit_ask_turn "Pick next iter"
72
- } > "$TRANSCRIPT"
73
- run run_hook
74
- [ "$status" -eq 0 ]
75
- [[ "$output" == *"stopReason"* ]]
76
- }
77
-
78
- @test "detect: stopReason cites P130 + framework-prescribed halt points" {
79
- {
80
- printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
81
- emit_orchestrator_activation
82
- emit_text_turn "Iter 1 done."
83
- emit_ask_turn "Next problem"
84
- } > "$TRANSCRIPT"
85
- run run_hook
86
- [ "$status" -eq 0 ]
87
- [[ "$output" == *"P130"* ]]
88
- [[ "$output" == *"halt point"* ]]
89
- [[ "$output" == *"outstanding_questions"* ]]
90
- }
91
-
92
- @test "detect: stopReason cites ADR-044 framework-resolution boundary" {
93
- {
94
- printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
95
- emit_orchestrator_activation
96
- emit_text_turn "Iter 1 done."
97
- emit_ask_turn "Pick"
98
- } > "$TRANSCRIPT"
99
- run run_hook
100
- [ "$status" -eq 0 ]
101
- [[ "$output" == *"ADR-044"* ]]
102
- }
103
-
104
- # --- Negative paths: silent exit ---
105
-
106
- @test "allow: transcript with no orchestrator activation exits silently" {
107
- # User asked a question outside /wr-itil:work-problems context;
108
- # AskUserQuestion in this case is unrelated to mid-loop discipline.
109
- {
110
- printf '{"type":"user","message":{"role":"user","content":"help me design a feature"}}\n'
111
- emit_text_turn "Two paths come to mind."
112
- emit_ask_turn "Design choice"
113
- } > "$TRANSCRIPT"
114
- run run_hook
115
- [ "$status" -eq 0 ]
116
- [[ "$output" != *"stopReason"* ]]
117
- }
118
-
119
- @test "allow: orchestrator activated then ALL_DONE emitted (post-loop wrap)" {
120
- # The orchestrator has emitted its terminal summary; subsequent
121
- # AskUserQuestion is post-loop interactive follow-up, not mid-loop.
122
- {
123
- printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
124
- emit_orchestrator_activation
125
- emit_text_turn "Iter 1 complete."
126
- emit_text_turn "## Work Problems Summary
127
- All iters complete.
128
- ALL_DONE"
129
- emit_ask_turn "Follow-up question"
130
- } > "$TRANSCRIPT"
131
- run run_hook
132
- [ "$status" -eq 0 ]
133
- [[ "$output" != *"stopReason"* ]]
134
- }
135
-
136
- @test "allow: orchestrator activated then Work Problems Summary header emitted (post-loop)" {
137
- {
138
- printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
139
- emit_orchestrator_activation
140
- emit_text_turn "## Work Problems Summary
141
-
142
- Completed: 3 iters."
143
- emit_ask_turn "Next steps?"
144
- } > "$TRANSCRIPT"
145
- run run_hook
146
- [ "$status" -eq 0 ]
147
- [[ "$output" != *"stopReason"* ]]
148
- }
149
-
150
- @test "allow: last assistant turn does not contain AskUserQuestion" {
151
- {
152
- printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
153
- emit_orchestrator_activation
154
- emit_text_turn "Iter 2 dispatched."
155
- } > "$TRANSCRIPT"
156
- run run_hook
157
- [ "$status" -eq 0 ]
158
- [[ "$output" != *"stopReason"* ]]
159
- }
160
-
161
- @test "allow: missing transcript_path exits silently" {
162
- run bash -c 'echo "{\"session_id\":\"sid\"}" | bash "$1"' -- "$HOOK"
163
- [ "$status" -eq 0 ]
164
- [[ "$output" != *"stopReason"* ]]
165
- }
166
-
167
- @test "allow: non-existent transcript file exits silently" {
168
- run bash -c "echo '{\"session_id\":\"sid\",\"transcript_path\":\"/tmp/does-not-exist-$RANDOM\"}' | bash '$HOOK'"
169
- [ "$status" -eq 0 ]
170
- [[ "$output" != *"stopReason"* ]]
171
- }
172
-
173
- @test "allow: empty transcript exits silently" {
174
- : > "$TRANSCRIPT"
175
- run run_hook
176
- [ "$status" -eq 0 ]
177
- [[ "$output" != *"stopReason"* ]]
178
- }
179
-
180
- @test "allow: malformed JSONL lines do not crash the hook" {
181
- {
182
- echo "not-json"
183
- emit_orchestrator_activation
184
- emit_text_turn "Iter 2"
185
- } > "$TRANSCRIPT"
186
- run run_hook
187
- [ "$status" -eq 0 ]
188
- # Either silent OR stopReason — but never a crash. We assert no
189
- # non-zero exit; the silent-vs-stopReason split is incidental here.
190
- }
191
-
192
- # --- Advisory budget per ADR-045 ---
193
-
194
- @test "advisory output stays under ADR-045 800-byte honour-system band" {
195
- {
196
- printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
197
- emit_orchestrator_activation
198
- emit_text_turn "Iter 1 done."
199
- emit_ask_turn "Pick"
200
- } > "$TRANSCRIPT"
201
- run run_hook
202
- [ "$status" -eq 0 ]
203
- [[ "$output" == *"stopReason"* ]]
204
- [ "${#output}" -lt 1000 ]
205
- }
206
-
207
- # --- Distinguishing-marker: tool_name for AskUserQuestion --
208
-
209
- @test "detect: matches even when AskUserQuestion is intermixed with text blocks" {
210
- {
211
- printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
212
- emit_orchestrator_activation
213
- cat <<'JSON'
214
- {"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"Two iter targets are tied on WSJF:"},{"type":"tool_use","name":"AskUserQuestion","input":{"questions":[{"question":"Pick next iter","header":"Next iter","options":[{"label":"P132","description":"x"},{"label":"P130","description":"y"}]}]}}]}}
215
- JSON
216
- } > "$TRANSCRIPT"
217
- run run_hook
218
- [ "$status" -eq 0 ]
219
- [[ "$output" == *"stopReason"* ]]
220
- }
@@ -1,210 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Behavioural tests for itil-no-implement-draft-gate.sh (ADR-096 / P404).
3
- # PreToolUse:Bash — reads a JSON envelope on stdin, emits permissionDecision:deny
4
- # (exit 0, deny in the JSON) when a commit references a DRAFT story.
5
- # @adr ADR-096 @adr ADR-052 @problem P404
6
-
7
- setup() {
8
- HOOK="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)/itil-no-implement-draft-gate.sh"
9
- MARK="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../scripts" && pwd)/mark-story-oversight-confirmed.sh"
10
- TMP="$(mktemp -d)"; cd "$TMP"; git init -q .
11
- mkdir -p docs/stories/draft docs/stories/accepted docs/stories/in-progress
12
- }
13
-
14
- # Seed a minimally well-formed story. Since ADR-101 the gate is ratification-
15
- # aware, so a bare `touch` no longer produces a story it will pass.
16
- seed_story() { printf -- '---\nstatus: accepted\n---\n\n# %s\n' "$1" > "$2"; }
17
- # Ratify via the real write path, never a hand-written marker — the hash has one
18
- # definition and a hand-rolled fixture would drift from it.
19
- ratify() { bash "$MARK" "$@" >/dev/null 2>&1; }
20
- teardown() { cd /; rm -rf "$TMP"; }
21
-
22
- # write env.json carrying the given command string
23
- env_cmd() { python3 -c 'import json,sys; open("env.json","w").write(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$1"; }
24
-
25
- @test "blocks a commit referencing a DRAFT story" {
26
- touch docs/stories/draft/STORY-042-foo.md
27
- env_cmd 'git commit -m "fix: thing
28
-
29
- Refs: STORY-042"'
30
- run bash -c "bash '$HOOK' < env.json"
31
- [ "$status" -eq 0 ]
32
- echo "$output" | grep -q '"permissionDecision": "deny"'
33
- echo "$output" | grep -q 'STORY-042'
34
- }
35
-
36
- # This case previously seeded an EMPTY, unratified accepted story and asserted
37
- # allow — the P465 hole encoded as a test rather than behaviour anyone chose.
38
- # ADR-096 always claimed no unratified story could be implemented; nothing
39
- # enforced it. Split into both directions, flipped in the slice that ships the
40
- # behaviour (the ADR-089 precedent).
41
-
42
- @test "allows a commit referencing an ACCEPTED and RATIFIED story" {
43
- seed_story STORY-042 docs/stories/accepted/STORY-042-foo.md
44
- ratify docs/stories/accepted/STORY-042-foo.md
45
- env_cmd 'git commit -m "fix: thing
46
-
47
- Refs: STORY-042"'
48
- run bash -c "bash '$HOOK' < env.json"
49
- [ "$status" -eq 0 ]
50
- ! echo "$output" | grep -q 'deny'
51
- }
52
-
53
- @test "blocks a commit referencing an ACCEPTED but UNRATIFIED story (P465)" {
54
- seed_story STORY-042 docs/stories/accepted/STORY-042-foo.md
55
- env_cmd 'git commit -m "fix: thing
56
-
57
- Refs: STORY-042"'
58
- run bash -c "bash '$HOOK' < env.json"
59
- [ "$status" -eq 0 ]
60
- echo "$output" | grep -q '"permissionDecision": "deny"'
61
- echo "$output" | grep -q 'not ratified'
62
- }
63
-
64
- @test "blocks a commit referencing an IN-PROGRESS story whose content has drifted since ratification" {
65
- seed_story STORY-042 docs/stories/in-progress/STORY-042-foo.md
66
- ratify docs/stories/in-progress/STORY-042-foo.md
67
- printf -- '\nA substance edit made after ratification.\n' >> docs/stories/in-progress/STORY-042-foo.md
68
- env_cmd 'git commit -m "fix: thing
69
-
70
- Refs: STORY-042"'
71
- run bash -c "bash '$HOOK' < env.json"
72
- [ "$status" -eq 0 ]
73
- echo "$output" | grep -q '"permissionDecision": "deny"'
74
- }
75
-
76
- @test "ticking an acceptance criterion is progress, not drift — commit still allowed" {
77
- cat > docs/stories/in-progress/STORY-042-foo.md <<'EOF'
78
- ---
79
- status: in-progress
80
- ---
81
-
82
- # STORY-042
83
-
84
- ## Acceptance criteria (accepted-gate, INVEST Testable)
85
-
86
- - [ ] The step happens.
87
- EOF
88
- ratify docs/stories/in-progress/STORY-042-foo.md
89
- sed -i.bak 's/- \[ \] The step happens./- [x] The step happens./' docs/stories/in-progress/STORY-042-foo.md
90
- rm -f docs/stories/in-progress/*.bak
91
- env_cmd 'git commit -m "fix: thing
92
-
93
- Refs: STORY-042"'
94
- run bash -c "bash '$HOOK' < env.json"
95
- [ "$status" -eq 0 ]
96
- ! echo "$output" | grep -q 'deny'
97
- }
98
-
99
- @test "ADR-101: a pure-decomposition story whose basis no longer matches its criteria is blocked" {
100
- cat > docs/stories/accepted/STORY-042-foo.md <<'EOF'
101
- ---
102
- status: accepted
103
- afk-accept: pure-decomposition
104
- ---
105
-
106
- # STORY-042
107
-
108
- ## Acceptance criteria (accepted-gate, INVEST Testable)
109
-
110
- - [ ] One.
111
- - [ ] Two.
112
-
113
- ## Decomposition basis
114
-
115
- - One decomposes ADR-900.
116
- EOF
117
- bash "$MARK" --pure-decomposition docs/stories/accepted/STORY-042-foo.md >/dev/null 2>&1
118
- env_cmd 'git commit -m "fix: thing
119
-
120
- Refs: STORY-042"'
121
- run bash -c "bash '$HOOK' < env.json"
122
- [ "$status" -eq 0 ]
123
- echo "$output" | grep -q '"permissionDecision": "deny"'
124
- echo "$output" | grep -q 'Decomposition basis'
125
- }
126
-
127
- @test "ADR-101: a well-formed pure-decomposition story is allowed" {
128
- cat > docs/stories/accepted/STORY-042-foo.md <<'EOF'
129
- ---
130
- status: accepted
131
- afk-accept: pure-decomposition
132
- ---
133
-
134
- # STORY-042
135
-
136
- ## Acceptance criteria (accepted-gate, INVEST Testable)
137
-
138
- - [ ] One.
139
- - [ ] Two.
140
-
141
- ## Decomposition basis
142
-
143
- - One decomposes ADR-900.
144
- - Two decomposes ADR-900.
145
- EOF
146
- bash "$MARK" --pure-decomposition docs/stories/accepted/STORY-042-foo.md >/dev/null 2>&1
147
- env_cmd 'git commit -m "fix: thing
148
-
149
- Refs: STORY-042"'
150
- run bash -c "bash '$HOOK' < env.json"
151
- [ "$status" -eq 0 ]
152
- ! echo "$output" | grep -q 'deny'
153
- }
154
-
155
- @test "a DONE story is past implementation and is not ratification-gated" {
156
- mkdir -p docs/stories/done
157
- touch docs/stories/done/STORY-042-foo.md
158
- env_cmd 'git commit -m "fix: thing
159
-
160
- Refs: STORY-042"'
161
- run bash -c "bash '$HOOK' < env.json"
162
- [ "$status" -eq 0 ]
163
- ! echo "$output" | grep -q 'deny'
164
- }
165
-
166
- @test "exempts a capture commit even for a draft story" {
167
- touch docs/stories/draft/STORY-042-foo.md
168
- env_cmd 'git commit -m "feat(itil): capture STORY-042 foo
169
-
170
- Refs: STORY-042"'
171
- run bash -c "bash '$HOOK' < env.json"
172
- [ "$status" -eq 0 ]
173
- ! echo "$output" | grep -q 'deny'
174
- }
175
-
176
- @test "bootstrap-exempt commit bypasses" {
177
- touch docs/stories/draft/STORY-042-foo.md
178
- env_cmd 'git commit -m "migrate
179
-
180
- Refs: STORY-042
181
- bootstrap-exempt: STORY-MAP-001"'
182
- run bash -c "bash '$HOOK' < env.json"
183
- [ "$status" -eq 0 ]
184
- ! echo "$output" | grep -q 'deny'
185
- }
186
-
187
- @test "non-commit command is a no-op" {
188
- touch docs/stories/draft/STORY-042-foo.md
189
- env_cmd 'echo Refs: STORY-042'
190
- run bash -c "bash '$HOOK' < env.json"
191
- [ "$status" -eq 0 ]
192
- ! echo "$output" | grep -q 'deny'
193
- }
194
-
195
- @test "commit with no story trailer is a no-op" {
196
- env_cmd 'git commit -m "fix: no story ref"'
197
- run bash -c "bash '$HOOK' < env.json"
198
- [ "$status" -eq 0 ]
199
- ! echo "$output" | grep -q 'deny'
200
- }
201
-
202
- @test "BYPASS env allows the commit" {
203
- touch docs/stories/draft/STORY-042-foo.md
204
- env_cmd 'git commit -m "fix
205
-
206
- Refs: STORY-042"'
207
- BYPASS_NO_IMPLEMENT_DRAFT=1 run bash -c "BYPASS_NO_IMPLEMENT_DRAFT=1 bash '$HOOK' < env.json"
208
- [ "$status" -eq 0 ]
209
- ! echo "$output" | grep -q 'deny'
210
- }