@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,310 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Behavioural tests for check-afk-accept-eligible.sh (ADR-101 / P456 / P465).
3
- # Each case maps onto an ADR-101 Confirmation item. Behavioural, not structural:
4
- # every test runs the real script against a real fixture tree and asserts on its
5
- # exit status and stderr, never on its source text (ADR-052 / P081).
6
- #
7
- # The POSITIVE case is the load-bearing one. An earlier revision shipped an
8
- # `awk -v` escape bug that made the checker permanently inert — it fails closed,
9
- # so no negative test could ever have caught it. Only asserting that a
10
- # well-formed story IS eligible surfaces that class of bug.
11
- #
12
- # @adr ADR-101 ADR-090 ADR-095 ADR-096 ADR-098 ADR-052 @problem P456 P465
13
-
14
- setup() {
15
- SCRIPTS="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
16
- CHECK="$SCRIPTS/check-afk-accept-eligible.sh"
17
- MARK="$SCRIPTS/mark-story-oversight-confirmed.sh"
18
- TMP="$(mktemp -d)"; cd "$TMP"
19
- mkdir -p docs/stories/draft docs/story-maps/draft docs/rfcs docs/jtbd/dev docs/problems/open docs/decisions
20
- export HOME="$TMP/home"; mkdir -p "$HOME/.claude"
21
-
22
- # --- confirmed parents -----------------------------------------------------
23
- printf -- '---\nhuman-oversight: confirmed\n---\n\n# ADR-900\n' > docs/decisions/900-a-confirmed-decision.proposed.md
24
- printf -- '---\nhuman-oversight: confirmed\n---\n\n# JTBD-900\n' > docs/jtbd/dev/JTBD-900-a-job.proposed.md
25
- printf -- '---\nhuman-oversight: confirmed\n---\n\n# persona\n' > docs/jtbd/dev/persona.md
26
- printf -- '---\nadrs: [ADR-900]\n---\n\n# RFC-900\n' > docs/rfcs/RFC-900-a-vehicle.proposed.md
27
- printf -- '# P900\n' > docs/problems/open/900-a-problem.md
28
-
29
- # A map that was ratified BEFORE the story's card was added — the common case,
30
- # since ADR-095 compels the card at capture.
31
- MAP=docs/story-maps/draft/STORY-MAP-900-a-map.html
32
- printf '<html><head>\n<a class="slice" data-story-id="STORY-800">old</a>\n</head></html>\n' > "$MAP"
33
- bash "$MARK" "$MAP" 2>/dev/null
34
- # Now add STORY-901's card, drifting the map exactly as capture would.
35
- python3 - "$MAP" <<'PY'
36
- import sys
37
- p=sys.argv[1]; s=open(p).read()
38
- open(p,"w").write(s.replace('</head>',' <a class="slice" data-story-id="STORY-901">new</a>\n</head>'))
39
- PY
40
-
41
- export WR_ITIL_AFK_ACCEPT=1
42
- }
43
- teardown() { cd /; rm -rf "$TMP"; }
44
-
45
- # A well-formed pure-decomposition story: 2 criteria, 2 basis entries, all
46
- # citations traced and confirmed.
47
- seed_story() {
48
- cat > docs/stories/draft/STORY-901-a-story.md <<'EOF'
49
- ---
50
- status: draft
51
- problems: [P900]
52
- jtbd: [JTBD-900]
53
- rfcs: [RFC-900]
54
- story-maps: [STORY-MAP-900]
55
- adrs: [ADR-900]
56
- afk-accept: pure-decomposition
57
- ---
58
-
59
- # STORY-901: A story
60
-
61
- ## User value
62
-
63
- In order to land confirmed work, as a developer, I want the loop to proceed.
64
-
65
- ## Acceptance criteria (accepted-gate, INVEST Testable)
66
-
67
- - [ ] The first step happens.
68
- - [ ] The second step happens.
69
-
70
- ## Decomposition basis
71
-
72
- - Criterion 1 decomposes ADR-900's rule about the first step.
73
- - Criterion 2 decomposes ADR-900's rule about the second step.
74
- EOF
75
- }
76
- run_check() { run bash "$CHECK" docs/stories/draft/STORY-901-a-story.md \
77
- docs/story-maps docs/rfcs docs/jtbd docs/problems docs/decisions; }
78
-
79
- # --- ADR-101 Confirmation: eligibility ---------------------------------------
80
-
81
- @test "ELIGIBLE: pure-decomposition story whose parents are all confirmed" {
82
- seed_story; run_check
83
- [ "$status" -eq 0 ]
84
- echo "$output" | grep -q 'ELIGIBLE'
85
- }
86
-
87
- @test "NOT eligible: a traced ADR parent is unconfirmed" {
88
- seed_story
89
- printf -- '---\nhuman-oversight: unconfirmed\n---\n\n# ADR-900\n' > docs/decisions/900-a-confirmed-decision.proposed.md
90
- run_check
91
- [ "$status" -eq 1 ]
92
- echo "$output" | grep -q 'ADR-900'
93
- }
94
-
95
- @test "NOT eligible: a traced JTBD's persona is unconfirmed" {
96
- seed_story
97
- printf -- '---\nhuman-oversight: unconfirmed\n---\n\n# persona\n' > docs/jtbd/dev/persona.md
98
- run_check
99
- [ "$status" -eq 1 ]
100
- echo "$output" | grep -qi 'persona'
101
- }
102
-
103
- @test "NOT eligible: a traced artefact does not resolve (new substance)" {
104
- seed_story
105
- rm docs/decisions/900-a-confirmed-decision.proposed.md
106
- run_check
107
- [ "$status" -eq 1 ]
108
- }
109
-
110
- @test "NOT eligible: basis entries do not match the criteria count" {
111
- seed_story
112
- printf -- '- [ ] A third step nobody accounted for.\n' >> docs/stories/draft/STORY-901-a-story.md
113
- run_check
114
- [ "$status" -eq 1 ]
115
- echo "$output" | grep -q 'Decomposition basis'
116
- }
117
-
118
- @test "NOT eligible: basis cites an artefact condition (a) never verified" {
119
- seed_story
120
- sed -i.bak 's/ADR-900.s rule about the first step/ADR-999 rule about the first step/' docs/stories/draft/STORY-901-a-story.md
121
- run_check
122
- [ "$status" -eq 1 ]
123
- echo "$output" | grep -q 'ADR-999'
124
- }
125
-
126
- @test "NOT eligible: the story does not declare the carve-out" {
127
- seed_story
128
- sed -i.bak '/^afk-accept:/d' docs/stories/draft/STORY-901-a-story.md
129
- run_check
130
- [ "$status" -eq 1 ]
131
- echo "$output" | grep -q 'afk-accept'
132
- }
133
-
134
- @test "NOT eligible: no acceptance criteria at all (fail-closed on zero)" {
135
- seed_story
136
- sed -i.bak 's/^- \[ \] The first step happens.//; s/^- \[ \] The second step happens.//' docs/stories/draft/STORY-901-a-story.md
137
- run_check
138
- [ "$status" -eq 1 ]
139
- }
140
-
141
- # --- ADR-101 Confirmation: the secondary blacklist ---------------------------
142
-
143
- @test "NOT eligible: an open-decision marker in ordinary prose" {
144
- seed_story
145
- printf -- '\nThe storage locus is still to be decided.\n' >> docs/stories/draft/STORY-901-a-story.md
146
- run_check
147
- [ "$status" -eq 1 ]
148
- }
149
-
150
- @test "ELIGIBLE: the same vocabulary inside a fenced or backticked span" {
151
- seed_story
152
- printf -- '\nThe checker rejects the phrase `to be decided` when it appears in prose:\n\n```\nopen question / TBD / decision needed\n```\n' \
153
- >> docs/stories/draft/STORY-901-a-story.md
154
- run_check
155
- [ "$status" -eq 0 ]
156
- }
157
-
158
- # --- ADR-101 Confirmation: the map leg disjunction ---------------------------
159
-
160
- @test "ELIGIBLE: map re-ratified WITH the story's card already present" {
161
- seed_story
162
- bash "$MARK" "$MAP" 2>/dev/null # re-ratify now that STORY-901's card exists
163
- run_check
164
- [ "$status" -eq 0 ]
165
- }
166
-
167
- @test "NOT eligible: map drifted for a reason OTHER than the story's own card" {
168
- seed_story
169
- printf '<p>an unrelated edit</p>\n' >> "$MAP"
170
- run_check
171
- [ "$status" -eq 1 ]
172
- echo "$output" | grep -q 'STORY-MAP-900'
173
- }
174
-
175
- @test "NOT eligible: map carries no human-oversight marker at all" {
176
- seed_story
177
- grep -v 'oversight' "$MAP" > "$MAP.tmp" && mv "$MAP.tmp" "$MAP"
178
- run_check
179
- [ "$status" -eq 1 ]
180
- }
181
-
182
- # --- ADR-101 Confirmation: the opt-in split ----------------------------------
183
-
184
- @test "NOT eligible without opt-in, even when (a) and (b) both hold" {
185
- seed_story
186
- unset WR_ITIL_AFK_ACCEPT
187
- run_check
188
- [ "$status" -eq 1 ]
189
- echo "$output" | grep -q 'opted in'
190
- }
191
-
192
- @test "project config opts in" {
193
- seed_story
194
- unset WR_ITIL_AFK_ACCEPT
195
- mkdir -p .claude
196
- printf '{ "afk_accept_pure_decomposition": true }\n' > .claude/itil.config.json
197
- run_check
198
- [ "$status" -eq 0 ]
199
- }
200
-
201
- @test "a non-boolean config value does NOT opt in" {
202
- seed_story
203
- unset WR_ITIL_AFK_ACCEPT
204
- mkdir -p .claude
205
- printf '{ "afk_accept_pure_decomposition": "true" }\n' > .claude/itil.config.json
206
- run_check
207
- [ "$status" -eq 1 ]
208
- }
209
-
210
- @test "an unparseable config does NOT opt in" {
211
- seed_story
212
- unset WR_ITIL_AFK_ACCEPT
213
- mkdir -p .claude
214
- printf 'not json at all\n' > .claude/itil.config.json
215
- run_check
216
- [ "$status" -eq 1 ]
217
- }
218
-
219
- @test "ADR-098 per-key fallback: a project file omitting the key falls through to machine" {
220
- seed_story
221
- unset WR_ITIL_AFK_ACCEPT
222
- mkdir -p .claude
223
- printf '{ "some_other_key": 1 }\n' > .claude/itil.config.json
224
- printf '{ "afk_accept_pure_decomposition": true }\n' > "$HOME/.claude/itil.config.json"
225
- run_check
226
- [ "$status" -eq 0 ]
227
- }
228
-
229
- @test "a project file setting the key FALSE wins over a machine TRUE" {
230
- seed_story
231
- unset WR_ITIL_AFK_ACCEPT
232
- mkdir -p .claude
233
- printf '{ "afk_accept_pure_decomposition": false }\n' > .claude/itil.config.json
234
- printf '{ "afk_accept_pure_decomposition": true }\n' > "$HOME/.claude/itil.config.json"
235
- run_check
236
- [ "$status" -eq 1 ]
237
- }
238
-
239
- @test "jq absent resolves to the built-in default: NOT eligible" {
240
- seed_story
241
- unset WR_ITIL_AFK_ACCEPT
242
- mkdir -p .claude bin
243
- printf '{ "afk_accept_pure_decomposition": true }\n' > .claude/itil.config.json
244
- run env PATH="/usr/bin:/bin" bash "$CHECK" docs/stories/draft/STORY-901-a-story.md \
245
- docs/story-maps docs/rfcs docs/jtbd docs/problems docs/decisions
246
- # Only meaningful where jq is genuinely off PATH; skip otherwise.
247
- if PATH="/usr/bin:/bin" command -v jq >/dev/null 2>&1; then skip "jq is on the minimal PATH here"; fi
248
- [ "$status" -eq 1 ]
249
- }
250
-
251
- # --- ADR-101 Confirmation: no automated path writes a `true` opt-in ----------
252
-
253
- @test "no shipped installer or scaffold writes an opt-in value" {
254
- # The guard that keeps opt-in from becoming opt-out-by-stealth. Any shipped
255
- # code that WRITES this key would defeat the split; reading it is fine.
256
- cd "$(dirname "$CHECK")/.."
257
- # Guard the search roots. Pointed at a directory that does not exist, grep
258
- # matches nothing and the assertion below passes for the wrong reason — and
259
- # whether it passes at all then depends on which grep merges its warning into
260
- # bats' $output.
261
- [ -d bin ] && [ -d hooks ]
262
- run grep -rIlE 'afk_accept_pure_decomposition' --include='*.mjs' --include='*.js' bin/ hooks/
263
- [ -z "$output" ]
264
- }
265
-
266
- # --- ADR-101 Confirmation: detector stdout contract --------------------------
267
-
268
- @test "detect-unratified-stories-maps stdout is byte-identical with and without the flag" {
269
- seed_story
270
- a="$(bash "$SCRIPTS/detect-unratified-stories-maps.sh" docs/stories docs/story-maps 2>/dev/null)"
271
- b="$(bash "$SCRIPTS/detect-unratified-stories-maps.sh" --with-afk-accepted docs/stories docs/story-maps 2>/dev/null)"
272
- [ "$a" = "$b" ]
273
- }
274
-
275
- @test "--with-afk-accepted surfaces the machine-accepted story on stderr" {
276
- seed_story
277
- run bash -c "bash '$SCRIPTS/detect-unratified-stories-maps.sh' --with-afk-accepted docs/stories docs/story-maps 2>&1 >/dev/null"
278
- echo "$output" | grep -q 'STORY-901'
279
- echo "$output" | grep -q 'AFK-ACCEPTED'
280
- }
281
-
282
- @test "the post-hoc drain still finds the story when oversight-basis is stripped" {
283
- # The union key. `oversight-basis` is excluded from the content hash, so
284
- # stripping it would otherwise hide a machine-accepted story from the drain;
285
- # the authored `afk-accept:` declaration is inside the hash and closes that.
286
- seed_story
287
- bash "$MARK" --pure-decomposition docs/stories/draft/STORY-901-a-story.md 2>/dev/null
288
- sed -i.bak '/^oversight-basis:/d' docs/stories/draft/STORY-901-a-story.md
289
- run bash -c "bash '$SCRIPTS/detect-unratified-stories-maps.sh' --with-afk-accepted docs/stories docs/story-maps 2>&1 >/dev/null"
290
- echo "$output" | grep -q 'STORY-901'
291
- }
292
-
293
- # --- the marker write path ---------------------------------------------------
294
-
295
- @test "--pure-decomposition records the basis AND leaves the story ratified" {
296
- seed_story
297
- bash "$MARK" --pure-decomposition docs/stories/draft/STORY-901-a-story.md 2>/dev/null
298
- grep -q '^oversight-basis: pure-decomposition' docs/stories/draft/STORY-901-a-story.md
299
- # The basis line is excluded from the hash, so the story must NOT read as
300
- # drifted the instant it is marked.
301
- run bash -c "source '$SCRIPTS/../lib/story-oversight.sh'; is_story_map_ratified docs/stories/draft/STORY-901-a-story.md"
302
- [ "$status" -eq 0 ]
303
- }
304
-
305
- @test "a plain re-ratify CLEARS a stale pure-decomposition basis" {
306
- seed_story
307
- bash "$MARK" --pure-decomposition docs/stories/draft/STORY-901-a-story.md 2>/dev/null
308
- bash "$MARK" docs/stories/draft/STORY-901-a-story.md 2>/dev/null
309
- ! grep -q '^oversight-basis:' docs/stories/draft/STORY-901-a-story.md
310
- }
@@ -1,172 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # @problem P351 — skills fail-soft-skip when their precondition config is
4
- # missing — should auto-bootstrap with user input as needed
5
- # rather than silently skipping.
6
- #
7
- # Contract: `check-fail-soft-skip-discipline.sh <repo-root>` walks
8
- # `<repo-root>/packages/*/skills/*/SKILL.md`, greps each file for the
9
- # tightened fail-soft-skip pattern set
10
- # (fail-soft skip|silently skip|skipping.*config|skipping.*not configured|
11
- # not configured.*skip), emits one `WARN <relpath>:<line> <pat>: ...`
12
- # line per match on stderr, and exits 0 in Phase 1 advisory mode
13
- # regardless of whether violations were found.
14
- #
15
- # @adr ADR-049 (bin/ on PATH shim — adopter-safe script resolution)
16
- # @adr ADR-052 (Behavioural bats default)
17
- # @adr ADR-040 (Advisory-then-load-bearing reusable pattern)
18
- # @adr ADR-013 Rule 6 (Non-interactive fail-safe — advisory exit 0)
19
- # @jtbd JTBD-001 (Enforce Governance — pattern-discipline lint)
20
- # @jtbd JTBD-101 (Extend the Suite — extensible pattern per skill site)
21
-
22
- setup() {
23
- SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
24
- SCRIPT="$SCRIPTS_DIR/check-fail-soft-skip-discipline.sh"
25
- FIXTURE_ROOT="$(mktemp -d)"
26
- }
27
-
28
- teardown() {
29
- rm -rf "$FIXTURE_ROOT"
30
- }
31
-
32
- # ── Existence + executable ──────────────────────────────────────────────────
33
-
34
- @test "check-fail-soft-skip-discipline: script exists" {
35
- [ -f "$SCRIPT" ]
36
- }
37
-
38
- @test "check-fail-soft-skip-discipline: script is executable" {
39
- [ -x "$SCRIPT" ]
40
- }
41
-
42
- # ── Phase 1 advisory exit-code contract ─────────────────────────────────────
43
-
44
- @test "Phase 1 advisory: exits 0 on a clean fixture" {
45
- mkdir -p "$FIXTURE_ROOT/packages/sample/skills/clean-skill"
46
- cat > "$FIXTURE_ROOT/packages/sample/skills/clean-skill/SKILL.md" <<'EOF'
47
- # Sample clean skill
48
-
49
- This skill auto-bootstraps any missing precondition config via
50
- AskUserQuestion. No fail-soft pattern present.
51
- EOF
52
- run "$SCRIPT" "$FIXTURE_ROOT"
53
- [ "$status" -eq 0 ]
54
- }
55
-
56
- @test "Phase 1 advisory: exits 0 even when violations present (default WR_FAIL_SOFT_SKIP_WARN_ONLY=1)" {
57
- mkdir -p "$FIXTURE_ROOT/packages/sample/skills/dirty-skill"
58
- cat > "$FIXTURE_ROOT/packages/sample/skills/dirty-skill/SKILL.md" <<'EOF'
59
- # Sample dirty skill
60
-
61
- This skill performs a fail-soft skip when the config is missing.
62
- EOF
63
- run "$SCRIPT" "$FIXTURE_ROOT"
64
- [ "$status" -eq 0 ]
65
- }
66
-
67
- # ── WARN-on-fixture: behavioural ────────────────────────────────────────────
68
-
69
- @test "WARN-on-fixture: matches 'fail-soft skip' literal" {
70
- mkdir -p "$FIXTURE_ROOT/packages/sample/skills/dirty-skill"
71
- cat > "$FIXTURE_ROOT/packages/sample/skills/dirty-skill/SKILL.md" <<'EOF'
72
- # Dirty skill
73
-
74
- When the file is missing emit a fail-soft skip and continue.
75
- EOF
76
- run "$SCRIPT" "$FIXTURE_ROOT"
77
- [ "$status" -eq 0 ]
78
- [[ "$output" == *"WARN"* ]]
79
- [[ "$output" == *"packages/sample/skills/dirty-skill/SKILL.md"* ]]
80
- [[ "$output" == *"fail-soft skip"* ]]
81
- }
82
-
83
- @test "WARN-on-fixture: matches 'silently skip' synonym" {
84
- mkdir -p "$FIXTURE_ROOT/packages/sample/skills/silent-skill"
85
- cat > "$FIXTURE_ROOT/packages/sample/skills/silent-skill/SKILL.md" <<'EOF'
86
- # Silent skill
87
-
88
- If config missing, silently skip the pass.
89
- EOF
90
- run "$SCRIPT" "$FIXTURE_ROOT"
91
- [ "$status" -eq 0 ]
92
- [[ "$output" == *"silently skip"* ]]
93
- }
94
-
95
- @test "WARN-on-fixture: matches tightened 'skipping.*config' shape" {
96
- mkdir -p "$FIXTURE_ROOT/packages/sample/skills/skipper-skill"
97
- cat > "$FIXTURE_ROOT/packages/sample/skills/skipper-skill/SKILL.md" <<'EOF'
98
- # Skipper skill
99
-
100
- Skipping the pass because the channels config is absent.
101
- EOF
102
- run "$SCRIPT" "$FIXTURE_ROOT"
103
- [ "$status" -eq 0 ]
104
- [[ "$output" == *"skipper-skill/SKILL.md"* ]]
105
- }
106
-
107
- # ── CLEAN-on-fixture: behavioural negative ──────────────────────────────────
108
-
109
- @test "CLEAN-on-fixture: no WARN emitted when SKILL.md is fail-soft-skip free" {
110
- mkdir -p "$FIXTURE_ROOT/packages/sample/skills/auto-bootstrap-skill"
111
- cat > "$FIXTURE_ROOT/packages/sample/skills/auto-bootstrap-skill/SKILL.md" <<'EOF'
112
- # Auto-bootstrap skill
113
-
114
- When the config file is missing, auto-bootstrap it via AskUserQuestion
115
- (interactive mode) or queue a config-direction outstanding_question
116
- (AFK mode). The skill resumes the original pass after bootstrap.
117
- EOF
118
- run "$SCRIPT" "$FIXTURE_ROOT"
119
- [ "$status" -eq 0 ]
120
- ! [[ "$output" == *"WARN"* ]]
121
- }
122
-
123
- @test "CLEAN-on-fixture: does NOT false-positive on legitimate per-channel skip prose (architect tightening)" {
124
- mkdir -p "$FIXTURE_ROOT/packages/sample/skills/per-channel-skill"
125
- cat > "$FIXTURE_ROOT/packages/sample/skills/per-channel-skill/SKILL.md" <<'EOF'
126
- # Per-channel skill
127
-
128
- On rate-limit, log advisory and skip that channel only — skipping the
129
- failing channel/report is fine because other channels proceed. This
130
- prose is the inverse of fail-soft-skip-on-missing-config and must NOT
131
- fire a WARN per the architect-tightened pattern set.
132
- EOF
133
- run "$SCRIPT" "$FIXTURE_ROOT"
134
- [ "$status" -eq 0 ]
135
- # The "fail-soft-skip-on-missing-config" hyphenated literal in the
136
- # prose does NOT contain a literal space-separated "fail-soft skip"
137
- # phrase, but the descriptive text does. Verify the script catches the
138
- # descriptive use and does NOT mistake the per-channel skip-prose for
139
- # the load-bearing pattern.
140
- # We expect EITHER zero WARNs (if the descriptive use is the only
141
- # hit) OR exactly the descriptive lines. Either way the per-channel
142
- # "skipping the failing channel/report" prose alone must NOT generate
143
- # a WARN.
144
- channel_only_warns=$(echo "$output" | grep -c "skipping the failing channel" || true)
145
- [ "$channel_only_warns" = "0" ]
146
- }
147
-
148
- # ── Phase 2 promotion: behavioural ──────────────────────────────────────────
149
-
150
- @test "Phase 2 promotion: exits 1 when WR_FAIL_SOFT_SKIP_WARN_ONLY=0 + violations present" {
151
- mkdir -p "$FIXTURE_ROOT/packages/sample/skills/dirty-skill"
152
- cat > "$FIXTURE_ROOT/packages/sample/skills/dirty-skill/SKILL.md" <<'EOF'
153
- # Dirty skill
154
-
155
- Fail-soft skip when missing.
156
- EOF
157
- WR_FAIL_SOFT_SKIP_WARN_ONLY=0 run "$SCRIPT" "$FIXTURE_ROOT"
158
- [ "$status" -eq 1 ]
159
- }
160
-
161
- # ── Usage / path-error contract ─────────────────────────────────────────────
162
-
163
- @test "Usage: exits 2 on missing repo-root directory" {
164
- run "$SCRIPT" "$FIXTURE_ROOT/does-not-exist"
165
- [ "$status" -eq 2 ]
166
- }
167
-
168
- @test "Usage: exits 2 on repo-root without packages/ subdir" {
169
- mkdir -p "$FIXTURE_ROOT/no-packages-here"
170
- run "$SCRIPT" "$FIXTURE_ROOT/no-packages-here"
171
- [ "$status" -eq 2 ]
172
- }
@@ -1,164 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # @problem P314 — Phase 2 (RFC-005 B3/B4): the fix-time propose-fix
4
- # RFC-trace gate. Before fix work commences on a Known Error, the
5
- # framework requires an RFC tracing the problem; if none exists, a
6
- # problem-traced skeleton RFC is auto-created (per ADR-073) rather than
7
- # blocked. This script is the load-bearing PREDICATE half of that gate
8
- # (ADR-060 I1 load-bearing-from-the-start carried forward): it detects
9
- # whether any RFC traces the problem and emits an auto-create directive
10
- # on stdout when none does. The CREATE half is skill-orchestrated
11
- # (delegates to /wr-itil:capture-rfc — the canonical ADR-070-compliant
12
- # problem-traced-skeleton vehicle, no duplication).
13
- #
14
- # Behavioural per ADR-052: assert on the script's exit code + stdout
15
- # directive given fixture RFC corpora — not on script source content
16
- # (no structural greps per P081).
17
- #
18
- # Contract:
19
- # - <problem-file> whose basename is `<NNN>-<slug>.md` → PID = P<NNN>.
20
- # - An RFC traces the problem when its frontmatter `problems:` array
21
- # contains the exact PID (boundary-safe: P31 / P3140 must NOT match
22
- # a P314 query).
23
- # - Trace present → exit 0, EMPTY stdout (fix proceeds; no auto-create).
24
- # - Trace absent → exit 0, stdout carries `no-rfc-trace: P<NNN>` directive
25
- # (NEVER a non-zero/block exit — ADR-073 auto-create-not-block).
26
- # - Missing problem file / no args → exit 2 (caller misuse), stderr usage.
27
- #
28
- # @adr ADR-072 (RFC required at the propose-fix step on a Known Error)
29
- # @adr ADR-073 (fix-time gate auto-creates a missing RFC, everywhere —
30
- # never blocks; hence exit 0 on the absent branch)
31
- # @adr ADR-071 (every fix goes through an RFC — unconditional, no carve-out)
32
- # @adr ADR-060 (I1 load-bearing-from-the-start; I13 fix-proposal invariant)
33
- # @adr ADR-052 (behavioural bats default)
34
- # @jtbd JTBD-008 (Decompose a Fix Into Coordinated Changes — trace invariant)
35
- # @jtbd JTBD-006 (Progress the Backlog While I'm Away — never stall/skip)
36
-
37
- setup() {
38
- SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
39
- SCRIPT="$SCRIPTS_DIR/check-fix-rfc-trace.sh"
40
- RFCS_DIR="$(mktemp -d)"
41
- PROBLEMS_DIR="$(mktemp -d)"
42
- }
43
-
44
- teardown() {
45
- rm -rf "$RFCS_DIR" "$PROBLEMS_DIR"
46
- }
47
-
48
- # Write an RFC fixture whose frontmatter `problems:` array is set verbatim.
49
- write_rfc() {
50
- local id="$1" slug="$2" status="$3" problems="$4"
51
- cat > "$RFCS_DIR/RFC-${id}-${slug}.${status}.md" <<EOF
52
- ---
53
- status: ${status}
54
- rfc-id: ${slug}
55
- problems: ${problems}
56
- ---
57
-
58
- # RFC-${id}: ${slug}
59
- EOF
60
- }
61
-
62
- # Write a problem fixture; returns the path on stdout.
63
- write_problem() {
64
- local num="$1" slug="${2:-some-problem}"
65
- local f="$PROBLEMS_DIR/${num}-${slug}.md"
66
- cat > "$f" <<EOF
67
- # Problem ${num}: ${slug}
68
-
69
- **Status**: Known Error
70
- EOF
71
- printf '%s' "$f"
72
- }
73
-
74
- @test "trace present (single-PID array) → exit 0, empty stdout" {
75
- write_rfc 005 some-fix accepted "[P314]"
76
- pf="$(write_problem 314)"
77
- run "$SCRIPT" "$pf" "$RFCS_DIR"
78
- [ "$status" -eq 0 ]
79
- [ -z "$output" ]
80
- }
81
-
82
- @test "trace present (multi-PID array) → exit 0, empty stdout" {
83
- write_rfc 005 some-fix accepted "[P100, P314, P200]"
84
- pf="$(write_problem 314)"
85
- run "$SCRIPT" "$pf" "$RFCS_DIR"
86
- [ "$status" -eq 0 ]
87
- [ -z "$output" ]
88
- }
89
-
90
- @test "trace absent (empty rfcs dir) → exit 0, auto-create directive on stdout" {
91
- pf="$(write_problem 314)"
92
- run "$SCRIPT" "$pf" "$RFCS_DIR"
93
- [ "$status" -eq 0 ]
94
- [[ "$output" == *"no-rfc-trace: P314"* ]]
95
- }
96
-
97
- @test "trace absent (RFCs exist but none claim this PID) → exit 0, directive" {
98
- write_rfc 005 other-fix accepted "[P251]"
99
- write_rfc 013 another accepted "[P346]"
100
- pf="$(write_problem 314)"
101
- run "$SCRIPT" "$pf" "$RFCS_DIR"
102
- [ "$status" -eq 0 ]
103
- [[ "$output" == *"no-rfc-trace: P314"* ]]
104
- }
105
-
106
- @test "PID boundary: P31 in an RFC does NOT satisfy a P314 query" {
107
- write_rfc 005 short-pid accepted "[P31]"
108
- pf="$(write_problem 314)"
109
- run "$SCRIPT" "$pf" "$RFCS_DIR"
110
- [ "$status" -eq 0 ]
111
- [[ "$output" == *"no-rfc-trace: P314"* ]]
112
- }
113
-
114
- @test "PID boundary: P3140 in an RFC does NOT satisfy a P314 query" {
115
- write_rfc 005 long-pid accepted "[P3140]"
116
- pf="$(write_problem 314)"
117
- run "$SCRIPT" "$pf" "$RFCS_DIR"
118
- [ "$status" -eq 0 ]
119
- [[ "$output" == *"no-rfc-trace: P314"* ]]
120
- }
121
-
122
- @test "exact match works for a zero-padded low PID (P080 ← [P080])" {
123
- # PIDs are canonically 3-digit zero-padded (filenames 080-..., citations P080).
124
- write_rfc 005 padded-pid accepted "[P080]"
125
- pf="$(write_problem 080)"
126
- run "$SCRIPT" "$pf" "$RFCS_DIR"
127
- [ "$status" -eq 0 ]
128
- [ -z "$output" ]
129
- }
130
-
131
- @test "default rfcs-dir is docs/rfcs when second arg omitted" {
132
- # Run from a temp cwd containing docs/rfcs with a tracing RFC.
133
- workdir="$(mktemp -d)"
134
- mkdir -p "$workdir/docs/rfcs"
135
- cat > "$workdir/docs/rfcs/RFC-005-x.accepted.md" <<'EOF'
136
- ---
137
- problems: [P314]
138
- ---
139
- # RFC-005: x
140
- EOF
141
- pf="$(write_problem 314)"
142
- run bash -c "cd '$workdir' && '$SCRIPT' '$pf'"
143
- [ "$status" -eq 0 ]
144
- [ -z "$output" ]
145
- rm -rf "$workdir"
146
- }
147
-
148
- @test "missing problem file → exit 2, stderr usage" {
149
- run "$SCRIPT" "$PROBLEMS_DIR/999-nonexistent.md" "$RFCS_DIR"
150
- [ "$status" -eq 2 ]
151
- }
152
-
153
- @test "no args → exit 2" {
154
- run "$SCRIPT"
155
- [ "$status" -eq 2 ]
156
- }
157
-
158
- @test "directive names the canonical auto-create vehicle (capture-rfc) and ADRs" {
159
- pf="$(write_problem 314)"
160
- run "$SCRIPT" "$pf" "$RFCS_DIR"
161
- [ "$status" -eq 0 ]
162
- [[ "$output" == *"capture-rfc"* ]]
163
- [[ "$output" == *"ADR-073"* ]]
164
- }