@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,469 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # @problem P238 — Phase 3b renderer behavioural confirmation.
4
- # @problem P087 — parent: plugin maturity battle-hardening signal.
5
- #
6
- # Contract under test: `packages/itil/scripts/plugin-maturity-render.sh`
7
- # reads `plugin.json` `maturity:` field (per Phase 3a populate output)
8
- # and writes a prose-woven rollup badge into each plugin's README.md
9
- # value-framing lead prose AND populates a per-skill `Maturity` column
10
- # in the existing `## Skills` table. Idempotent — re-running with
11
- # unchanged inputs produces byte-identical README output.
12
- #
13
- # Anti-patterns enforced (ADR-063 §README badge rendering format):
14
- # - NO standalone `## Maturity` section
15
- # - NO header block immediately after H1 before any prose framing
16
- # - NO shields.io URL or inline SVG (markdown text only)
17
- #
18
- # Bootstrapping rendering: rollup carries compound form during the
19
- # suite-bootstrap window; per-skill column carries band name only
20
- # (compound stays at rollup, never at cell).
21
- #
22
- # @adr ADR-063 (Plugin maturity presentation layer — Phase 3b contract)
23
- # @adr ADR-053 (Plugin maturity taxonomy — Bootstrapping clause rendering)
24
- # @adr ADR-051 (JTBD-anchored README — prose-weaving precedent)
25
- # @adr ADR-049 (Shim grammar — `wr-itil-plugin-maturity-render` on $PATH)
26
- # @adr ADR-052 (Behavioural tests default)
27
- # @adr ADR-013 Rule 6 (non-interactive fail-safe — exit 0 always)
28
-
29
- setup() {
30
- SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
31
- SCRIPT="$SCRIPTS_DIR/plugin-maturity-render.sh"
32
- FIXTURE_DIR="$(mktemp -d)"
33
- PROJECT_ROOT="$FIXTURE_DIR/project"
34
- mkdir -p "$PROJECT_ROOT/packages"
35
- }
36
-
37
- teardown() {
38
- rm -rf "$FIXTURE_DIR"
39
- }
40
-
41
- # Helper: write a synthetic plugin layout with plugin.json + README.md
42
- make_plugin() {
43
- local name="$1"
44
- local plugin_json="$2"
45
- local readme="$3"
46
- local pkg="$PROJECT_ROOT/packages/$name"
47
- mkdir -p "$pkg/.claude-plugin"
48
- printf '%s\n' "$plugin_json" > "$pkg/.claude-plugin/plugin.json"
49
- printf '%s\n' "$readme" > "$pkg/README.md"
50
- }
51
-
52
- # ── Pre-checks ──────────────────────────────────────────────────────────────
53
-
54
- @test "script file exists and is executable" {
55
- [ -f "$SCRIPT" ]
56
- [ -x "$SCRIPT" ]
57
- }
58
-
59
- @test "missing packages dir exits 0 with stderr comment" {
60
- run bash "$SCRIPT" --project-root="$FIXTURE_DIR/does-not-exist"
61
- [ "$status" -eq 0 ]
62
- }
63
-
64
- @test "opt-out marker present: skips all writes" {
65
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Alpha"}}' \
66
- "# @windyroad/stub
67
-
68
- **Stub plugin description.**
69
-
70
- ## Skills
71
-
72
- | Skill | Purpose |
73
- |-------|---------|
74
- | /wr-stub:thing | Does a thing |
75
- "
76
- mkdir -p "$PROJECT_ROOT/.claude"
77
- touch "$PROJECT_ROOT/.claude/.skill-metrics-opt-out"
78
- local before; before="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
79
-
80
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
81
- [ "$status" -eq 0 ]
82
-
83
- local after; after="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
84
- [ "$before" = "$after" ]
85
- }
86
-
87
- # ── Confirmation #1 (ADR-063): rollup badge prose-woven into lead prose ─────
88
-
89
- @test "rollup badge: inserts prose-woven Maturity span into bold lead prose line" {
90
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Alpha"}}' \
91
- "# @windyroad/stub
92
-
93
- **Stub plugin description.** Some more prose.
94
-
95
- ## Skills
96
-
97
- | Skill | Purpose |
98
- |-------|---------|
99
- | /wr-stub:thing | Does a thing |
100
- "
101
-
102
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
103
- [ "$status" -eq 0 ]
104
-
105
- local out; out="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
106
- # Prose-woven Maturity span appears, italicised, in the lead-prose area
107
- [[ "$out" == *"*Maturity: Alpha"* ]]
108
- }
109
-
110
- @test "rollup badge: bootstrapping window renders compound form with invocation count" {
111
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Experimental","bootstrapping":true,"rollup_invocations_30d":796}}' \
112
- "# @windyroad/stub
113
-
114
- **Stub plugin description.**
115
-
116
- ## Skills
117
-
118
- | Skill | Purpose |
119
- |-------|---------|
120
- | /wr-stub:thing | Does a thing |
121
- "
122
-
123
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
124
- [ "$status" -eq 0 ]
125
-
126
- local out; out="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
127
- [[ "$out" == *"Experimental"* ]]
128
- [[ "$out" == *"suite-bootstrap window"* ]]
129
- [[ "$out" == *"796 invocations"* ]]
130
- }
131
-
132
- @test "rollup badge: post-bootstrap renders band name only (no compound)" {
133
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Beta"}}' \
134
- "# @windyroad/stub
135
-
136
- **Stub plugin description.**
137
-
138
- ## Skills
139
-
140
- | Skill | Purpose |
141
- |-------|---------|
142
- | /wr-stub:thing | Does a thing |
143
- "
144
-
145
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
146
- [ "$status" -eq 0 ]
147
-
148
- local out; out="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
149
- [[ "$out" == *"*Maturity: Beta.*"* ]]
150
- [[ "$out" != *"suite-bootstrap"* ]]
151
- [[ "$out" != *"invocations"* ]]
152
- }
153
-
154
- # ── P269: AND-gated compound predicate — null rollup_invocations_30d → bare ─
155
-
156
- @test "rollup badge: bootstrapping=true + rollup_invocations_30d=null → bare-band (hook-only plugin)" {
157
- # P269: when populate writes bootstrapping=true but rollup_invocations_30d
158
- # is null (hook-only plugin — no countable surfaces), the renderer's
159
- # AND-gated compound predicate at plugin-maturity-render.sh:146 must fall
160
- # through to bare-band. `0 invocations / 30d` would lie; bare-band is the
161
- # honest fall-through.
162
- make_plugin "hookonly" '{"name":"wr-hookonly","version":"0.1.0","description":"Hook-only","maturity":{"schema_version":"2.0","band":"Experimental","bootstrapping":true,"rollup_invocations_30d":null}}' \
163
- "# @windyroad/hookonly
164
-
165
- **Hook-only plugin description.**
166
-
167
- ## Skills
168
-
169
- | Skill | Purpose |
170
- |-------|---------|
171
- | /wr-hookonly:thing | Does a thing |
172
- "
173
-
174
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
175
- [ "$status" -eq 0 ]
176
-
177
- local out; out="$(cat "$PROJECT_ROOT/packages/hookonly/README.md")"
178
- [[ "$out" == *"*Maturity: Experimental.*"* ]]
179
- [[ "$out" != *"suite-bootstrap"* ]]
180
- [[ "$out" != *"invocations"* ]]
181
- }
182
-
183
- # ── P269: AND-gated compound predicate — bootstrapping=false → bare-band ────
184
-
185
- @test "rollup badge: bootstrapping=false + rollup_invocations_30d=integer → bare-band (post-sunset)" {
186
- # P269: when bootstrapping has lapsed (suite_oldest_days >= 60), populate
187
- # writes bootstrapping=false. Even with a non-null rollup_invocations_30d,
188
- # the AND-gated predicate falls through to bare-band — the compound
189
- # rendering is scoped to the bootstrapping window per ADR-053 §Bootstrapping
190
- # clause Phase 3 rendering requirement.
191
- make_plugin "stedp" '{"name":"wr-stedp","version":"0.1.0","description":"Steady","maturity":{"schema_version":"2.0","band":"Beta","bootstrapping":false,"rollup_invocations_30d":1500}}' \
192
- "# @windyroad/stedp
193
-
194
- **Steady-state plugin description.**
195
-
196
- ## Skills
197
-
198
- | Skill | Purpose |
199
- |-------|---------|
200
- | /wr-stedp:thing | Does a thing |
201
- "
202
-
203
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
204
- [ "$status" -eq 0 ]
205
-
206
- local out; out="$(cat "$PROJECT_ROOT/packages/stedp/README.md")"
207
- [[ "$out" == *"*Maturity: Beta.*"* ]]
208
- [[ "$out" != *"suite-bootstrap"* ]]
209
- [[ "$out" != *"invocations"* ]]
210
- }
211
-
212
- # ── Confirmation #2 (ADR-063): per-skill Maturity column populated ──────────
213
-
214
- @test "per-skill column: adds Maturity column to existing Skills table" {
215
- make_plugin "stub" '{
216
- "name":"wr-stub","version":"0.1.0","description":"Stub",
217
- "maturity":{"schema_version":"2.0","band":"Alpha","skills":{
218
- "thing":{"schema_version":"2.0","band":"Alpha","computed_at":"2026-05-18T00:00:00Z","evidence":{"invocations_30d":50,"days_shipped":30,"closed_tickets_window":5,"breaking_change_age_days":null}},
219
- "widget":{"schema_version":"2.0","band":"Experimental","computed_at":"2026-05-18T00:00:00Z","evidence":{"invocations_30d":2,"days_shipped":5,"closed_tickets_window":0,"breaking_change_age_days":null}}
220
- }}
221
- }' \
222
- "# @windyroad/stub
223
-
224
- **Stub plugin description.**
225
-
226
- ## Skills
227
-
228
- | Skill | Purpose |
229
- |-------|---------|
230
- | /wr-stub:thing | Does a thing |
231
- | /wr-stub:widget | Widgets things |
232
- "
233
-
234
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
235
- [ "$status" -eq 0 ]
236
-
237
- local out; out="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
238
- # Header row gains Maturity column
239
- [[ "$out" == *"| Skill | Purpose | Maturity |"* ]]
240
- # Cells populated
241
- [[ "$out" == *"/wr-stub:thing"*"| Alpha |"* ]]
242
- [[ "$out" == *"/wr-stub:widget"*"| Experimental |"* ]]
243
- # Per-skill cell carries band name ONLY (no compound)
244
- [[ "$out" != *"| Alpha (suite"* ]]
245
- }
246
-
247
- # ── Idempotency: second run produces no diff ────────────────────────────────
248
-
249
- @test "idempotency: second run against unchanged plugin.json produces byte-equal README" {
250
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Alpha"}}' \
251
- "# @windyroad/stub
252
-
253
- **Stub plugin description.**
254
-
255
- ## Skills
256
-
257
- | Skill | Purpose |
258
- |-------|---------|
259
- | /wr-stub:thing | Does a thing |
260
- "
261
-
262
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
263
- [ "$status" -eq 0 ]
264
- local first; first="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
265
-
266
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
267
- [ "$status" -eq 0 ]
268
- local second; second="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
269
-
270
- [ "$first" = "$second" ]
271
- }
272
-
273
- @test "idempotency: existing Maturity badge gets replaced (not appended)" {
274
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Beta"}}' \
275
- "# @windyroad/stub
276
-
277
- **Stub plugin description.** *Maturity: Alpha.*
278
-
279
- ## Skills
280
-
281
- | Skill | Purpose |
282
- |-------|---------|
283
- | /wr-stub:thing | Does a thing |
284
- "
285
-
286
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
287
- [ "$status" -eq 0 ]
288
-
289
- local out; out="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
290
- # Beta replaced Alpha (no duplication)
291
- [[ "$out" == *"*Maturity: Beta"* ]]
292
- [[ "$out" != *"*Maturity: Alpha"* ]]
293
- # Single Maturity span (no duplication)
294
- local count
295
- count="$(grep -oE '\*Maturity: [^*]+\*' "$PROJECT_ROOT/packages/stub/README.md" | wc -l)"
296
- [ "$count" -eq 1 ]
297
- }
298
-
299
- # ── Anti-pattern: no standalone ## Maturity section emitted ─────────────────
300
-
301
- @test "anti-pattern: renderer never emits a standalone ## Maturity section" {
302
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Alpha"}}' \
303
- "# @windyroad/stub
304
-
305
- **Stub plugin description.**
306
-
307
- ## Skills
308
-
309
- | Skill | Purpose |
310
- |-------|---------|
311
- | /wr-stub:thing | Does a thing |
312
- "
313
-
314
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
315
- [ "$status" -eq 0 ]
316
-
317
- local out; out="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
318
- [[ "$out" != *"## Maturity"* ]]
319
- [[ "$out" != *"# Maturity"* ]]
320
- }
321
-
322
- @test "anti-pattern: no shields.io badge URL emitted" {
323
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Alpha"}}' \
324
- "# @windyroad/stub
325
-
326
- **Stub plugin description.**
327
-
328
- ## Skills
329
-
330
- | Skill | Purpose |
331
- |-------|---------|
332
- | /wr-stub:thing | Does a thing |
333
- "
334
-
335
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
336
- [ "$status" -eq 0 ]
337
-
338
- local out; out="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
339
- [[ "$out" != *"shields.io"* ]]
340
- [[ "$out" != *"img.shields"* ]]
341
- }
342
-
343
- # ── Fail-safe: missing maturity field is a no-op (Phase 3a not yet run) ─────
344
-
345
- @test "fail-safe: plugin.json without maturity: field is skipped" {
346
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub"}' \
347
- "# @windyroad/stub
348
-
349
- **Stub plugin description.**
350
-
351
- ## Skills
352
-
353
- | Skill | Purpose |
354
- |-------|---------|
355
- | /wr-stub:thing | Does a thing |
356
- "
357
- local before; before="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
358
-
359
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
360
- [ "$status" -eq 0 ]
361
-
362
- local after; after="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
363
- [ "$before" = "$after" ]
364
- }
365
-
366
- # ── Fail-safe: plugin without README is skipped ─────────────────────────────
367
-
368
- @test "fail-safe: plugin without README.md is silently skipped" {
369
- local pkg="$PROJECT_ROOT/packages/no-readme"
370
- mkdir -p "$pkg/.claude-plugin"
371
- echo '{"name":"wr-no-readme","version":"0.1.0","description":"No README","maturity":{"schema_version":"1.0","band":"Alpha"}}' > "$pkg/.claude-plugin/plugin.json"
372
-
373
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
374
- [ "$status" -eq 0 ]
375
- [ ! -f "$pkg/README.md" ]
376
- }
377
-
378
- # ── No-AskUserQuestion: ADR-044 silent-framework carve-out ──────────────────
379
-
380
- @test "ADR-044: renderer never invokes AskUserQuestion per re-render" {
381
- # Negative-presence behavioural assertion per ADR-052 §carve-out — the
382
- # renderer is mechanical (band already computed by Phase 3a) and must
383
- # not surface a consent gate per re-render. Scans combined stdout +
384
- # stderr output for any AskUserQuestion-token spelling, case-insensitive
385
- # per architect adjustment G to plugin-maturity-populate.bats.
386
- make_plugin "silentp" '{"name":"wr-silentp","version":"0.1.0","description":"Silent","maturity":{"schema_version":"1.0","band":"Alpha"}}' \
387
- "# @windyroad/silentp
388
-
389
- **Silent plugin description.**
390
-
391
- ## Skills
392
-
393
- | Skill | Purpose |
394
- |-------|---------|
395
- | /wr-silentp:thing | Does a thing |
396
- "
397
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
398
- [ "$status" -eq 0 ]
399
- printf '%s' "$output" | grep -i -E 'askuserquestion|<askuser' && return 1 || true
400
- }
401
-
402
- # ── No-network primitive: ADR-035 privacy posture ───────────────────────────
403
-
404
- @test "ADR-035: script body invokes no network primitive" {
405
- # Negative-presence behavioural assertion — the renderer reads
406
- # plugin.json + README.md from filesystem only; never reaches a
407
- # network endpoint. Mirrors plugin-maturity-populate.bats.
408
- run grep -E "(curl|wget|nc -|netcat|ssh |scp |rsync|http\.client|urllib|requests)" "$SCRIPT"
409
- [ "$status" -ne 0 ]
410
- }
411
-
412
- # ── Multi-plugin: renders each plugin independently ─────────────────────────
413
-
414
- @test "multi-plugin: renders each packages/<plugin>/README.md independently" {
415
- make_plugin "alpha" '{"name":"wr-alpha","version":"0.1.0","description":"Alpha","maturity":{"schema_version":"1.0","band":"Alpha"}}' \
416
- "# @windyroad/alpha
417
-
418
- **Alpha plugin description.**
419
-
420
- ## Skills
421
-
422
- | Skill | Purpose |
423
- |-------|---------|
424
- | /wr-alpha:thing | Does a thing |
425
- "
426
- make_plugin "bravo" '{"name":"wr-bravo","version":"0.1.0","description":"Bravo","maturity":{"schema_version":"1.0","band":"Beta"}}' \
427
- "# @windyroad/bravo
428
-
429
- **Bravo plugin description.**
430
-
431
- ## Skills
432
-
433
- | Skill | Purpose |
434
- |-------|---------|
435
- | /wr-bravo:thing | Does a thing |
436
- "
437
-
438
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
439
- [ "$status" -eq 0 ]
440
-
441
- local out_a; out_a="$(cat "$PROJECT_ROOT/packages/alpha/README.md")"
442
- local out_b; out_b="$(cat "$PROJECT_ROOT/packages/bravo/README.md")"
443
- [[ "$out_a" == *"*Maturity: Alpha"* ]]
444
- [[ "$out_b" == *"*Maturity: Beta"* ]]
445
- }
446
-
447
- # ── Dry-run: prints diff to stdout, does not write ──────────────────────────
448
-
449
- @test "dry-run: --dry-run flag prints intended diff to stdout without modifying README" {
450
- make_plugin "stub" '{"name":"wr-stub","version":"0.1.0","description":"Stub","maturity":{"schema_version":"1.0","band":"Alpha"}}' \
451
- "# @windyroad/stub
452
-
453
- **Stub plugin description.**
454
-
455
- ## Skills
456
-
457
- | Skill | Purpose |
458
- |-------|---------|
459
- | /wr-stub:thing | Does a thing |
460
- "
461
- local before; before="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
462
-
463
- run bash "$SCRIPT" --project-root="$PROJECT_ROOT" --dry-run
464
- [ "$status" -eq 0 ]
465
- [[ "$output" == *"Maturity: Alpha"* ]]
466
-
467
- local after; after="$(cat "$PROJECT_ROOT/packages/stub/README.md")"
468
- [ "$before" = "$after" ]
469
- }
@@ -1,208 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # @problem P263 — CI pre-publish manifest-validity gate. Adds the
4
- # `claude plugin validate` (non-strict) loop ADR-063
5
- # §Confirmation #11 names as the post-bats coverage
6
- # layer that catches P258-class manifest breakages
7
- # (recognised top-level key with wrong-typed content)
8
- # without rejecting the ADR-063 `maturity:` safe-
9
- # extension pattern that --strict would reject.
10
- #
11
- # Contract: `plugin-validate-ci-gate.sh` (invoked via ADR-049 shim
12
- # `wr-itil-plugin-validate-ci-gate`) walks every
13
- # `packages/*/.claude-plugin/plugin.json` in CWD, invokes `claude
14
- # plugin validate <plugin_dir>` (NON-strict) per plugin, and exits
15
- # non-zero if ANY plugin's manifest fails validation. The loop does
16
- # NOT short-circuit on first failure — every plugin is exercised so
17
- # the CI failure surfaces every defect at once.
18
- #
19
- # Behavioural test strategy (ADR-052): a programmable stub `claude`
20
- # on PATH simulates `claude plugin validate`. The stub exits 1 when
21
- # the manifest carries a top-level `hooks:` key whose body holds a
22
- # `schema_version` sub-key (the P258 reproduction class — recognised
23
- # key, wrong-typed content); exits 0 otherwise (including the ADR-063
24
- # top-level `maturity:` safe-extension shape — unrecognised key, warn-
25
- # only under non-strict). The stub captures the load-bearing
26
- # behavioural contract of `claude plugin validate` non-strict for
27
- # the two manifest shapes P263's design tension turns on. The real
28
- # CLI is exercised at the CI workflow layer (`.github/workflows/
29
- # ci.yml`) — split per ADR-052 (bats covers script-owned loop +
30
- # failure-aggregation behaviour with a faithful test double; CI
31
- # exercises the real CLI surface end-to-end).
32
- #
33
- # @adr ADR-063 Amendment 2026-05-18 §Confirmation #11 (the gate
34
- # criterion this script satisfies)
35
- # @adr ADR-049 (bin/ on PATH shim — `wr-itil-plugin-validate-ci-gate`)
36
- # @adr ADR-052 (Behavioural tests default — stub-claude faithfully
37
- # models the validator's non-strict exit contract for
38
- # the two manifest shapes P263 turns on)
39
- # @adr ADR-014 (single-commit grain — script + shim + bats + CI +
40
- # ADR amendment + changeset land together)
41
- # @adr ADR-022 (KE WSJF multiplier — informs prioritisation)
42
- # @jtbd JTBD-101 (Extend the Suite with New Plugins — primary
43
- # alignment; named Desired Outcome at L19 strengthened
44
- # by this gate)
45
- # @jtbd JTBD-202 (Pre-Flight Governance Checks Before Release —
46
- # secondary alignment; gate fires in Quality Gates job)
47
-
48
- setup() {
49
- SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
50
- SCRIPT="$SCRIPTS_DIR/plugin-validate-ci-gate.sh"
51
- SHIM="$(cd "$SCRIPTS_DIR/../bin" && pwd)/wr-itil-plugin-validate-ci-gate"
52
- FIXTURE_DIR="$(mktemp -d)"
53
- STUB_DIR="$FIXTURE_DIR/stub-bin"
54
- mkdir -p "$STUB_DIR"
55
- cd "$FIXTURE_DIR"
56
- mkdir -p packages
57
- write_stub_claude
58
- export PATH="$STUB_DIR:$PATH"
59
- }
60
-
61
- teardown() {
62
- cd /
63
- rm -rf "$FIXTURE_DIR"
64
- }
65
-
66
- # Programmable stub for `claude plugin validate <plugin_dir>`. Faithful
67
- # model of the non-strict exit contract for the two manifest shapes
68
- # P263 turns on:
69
- # - Top-level `hooks:` carrying a `schema_version` sub-key (the P258
70
- # reproduction — recognised key with wrong-typed content) → exit 1.
71
- # - Anything else (including ADR-063 top-level `maturity:` safe-
72
- # extension shape, where `maturity:` is unrecognised → warn-only
73
- # under non-strict) → exit 0.
74
- write_stub_claude() {
75
- cat > "$STUB_DIR/claude" <<'STUB'
76
- #!/usr/bin/env bash
77
- [[ "$1" == "plugin" && "$2" == "validate" ]] || { echo "stub: unsupported args $*" >&2; exit 2; }
78
- plugin_dir="$3"
79
- manifest="$plugin_dir/.claude-plugin/plugin.json"
80
- [ -f "$manifest" ] || { echo "stub: manifest not found at $manifest" >&2; exit 1; }
81
- # Detect P258 reproduction: top-level "hooks": { ... "schema_version": ... }
82
- if python3 -c "
83
- import json, sys
84
- with open(sys.argv[1]) as f:
85
- m = json.load(f)
86
- for key in ('hooks', 'skills', 'agents', 'commands'):
87
- v = m.get(key)
88
- if isinstance(v, dict):
89
- for sub in v.values():
90
- if isinstance(sub, dict) and 'schema_version' in sub:
91
- sys.exit(1)
92
- sys.exit(0)
93
- " "$manifest"; then
94
- echo "stub: $plugin_dir OK"
95
- exit 0
96
- else
97
- echo "stub: $plugin_dir Validation errors: hooks: Invalid input" >&2
98
- exit 1
99
- fi
100
- STUB
101
- chmod +x "$STUB_DIR/claude"
102
- }
103
-
104
- # Helper: write a synthetic plugin manifest at packages/<name>/.claude-plugin/plugin.json
105
- write_plugin() {
106
- local name="$1"
107
- local body="$2"
108
- mkdir -p "packages/$name/.claude-plugin"
109
- printf '%s\n' "$body" > "packages/$name/.claude-plugin/plugin.json"
110
- }
111
-
112
- # ── Existence / executable ──────────────────────────────────────────────────
113
-
114
- @test "plugin-validate-ci-gate: canonical script exists" {
115
- [ -f "$SCRIPT" ]
116
- }
117
-
118
- @test "plugin-validate-ci-gate: canonical script is executable" {
119
- [ -x "$SCRIPT" ]
120
- }
121
-
122
- @test "plugin-validate-ci-gate: ADR-049 shim exists" {
123
- [ -f "$SHIM" ]
124
- }
125
-
126
- @test "plugin-validate-ci-gate: ADR-049 shim is executable" {
127
- [ -x "$SHIM" ]
128
- }
129
-
130
- @test "plugin-validate-ci-gate: shim is thin (single exec line to canonical body)" {
131
- grep -qE '^exec .*plugin-validate-ci-gate\.sh' "$SHIM"
132
- }
133
-
134
- # ── Fixture A: positive — ADR-063 safe-extension shape passes ───────────────
135
-
136
- @test "plugin-validate-ci-gate: ADR-063 maturity: top-level safe-extension shape → exit 0" {
137
- write_plugin "alpha" '{
138
- "name": "alpha",
139
- "version": "1.0.0",
140
- "description": "test plugin",
141
- "maturity": {
142
- "schema_version": "2.0",
143
- "band": "Experimental"
144
- }
145
- }'
146
-
147
- run "$SCRIPT"
148
- [ "$status" -eq 0 ]
149
- }
150
-
151
- @test "plugin-validate-ci-gate: multiple plugins all ADR-063-shaped → exit 0" {
152
- write_plugin "alpha" '{"name":"alpha","version":"1.0.0","description":"t","maturity":{"schema_version":"2.0","band":"Experimental"}}'
153
- write_plugin "beta" '{"name":"beta","version":"1.0.0","description":"t","maturity":{"schema_version":"2.0","band":"Stable"}}'
154
- write_plugin "gamma" '{"name":"gamma","version":"1.0.0","description":"t"}'
155
-
156
- run "$SCRIPT"
157
- [ "$status" -eq 0 ]
158
- }
159
-
160
- # ── Fixture B: negative — P258 reproduction shape fails ─────────────────────
161
-
162
- @test "plugin-validate-ci-gate: P258 reproduction (top-level hooks: with schema_version) → exit 1" {
163
- write_plugin "broken" '{
164
- "name": "broken",
165
- "version": "1.0.0",
166
- "description": "test plugin with P258 mistake",
167
- "hooks": {
168
- "some-hook": {
169
- "schema_version": "1.0",
170
- "band": "Experimental"
171
- }
172
- }
173
- }'
174
-
175
- run "$SCRIPT"
176
- [ "$status" -ne 0 ]
177
- }
178
-
179
- @test "plugin-validate-ci-gate: mixed pass/fail loops every plugin (no short-circuit) → exit 1" {
180
- write_plugin "alpha" '{"name":"alpha","version":"1.0.0","description":"t","maturity":{"schema_version":"2.0","band":"Experimental"}}'
181
- write_plugin "broken" '{"name":"broken","version":"1.0.0","description":"t","hooks":{"h":{"schema_version":"1.0","band":"Experimental"}}}'
182
- write_plugin "gamma" '{"name":"gamma","version":"1.0.0","description":"t"}'
183
-
184
- run "$SCRIPT"
185
- [ "$status" -ne 0 ]
186
- # All three plugins must be exercised — no short-circuit on first failure.
187
- echo "$output" | grep -q "alpha"
188
- echo "$output" | grep -q "broken"
189
- echo "$output" | grep -q "gamma"
190
- }
191
-
192
- # ── No-plugins case (CI is always run against the monorepo tree, but the
193
- # fail-safe matters for adopter-tree invocation per ADR-049 portability).
194
-
195
- @test "plugin-validate-ci-gate: no plugins under packages/ → exit 0 (nothing to validate)" {
196
- # No packages/<name>/.claude-plugin/plugin.json written.
197
- run "$SCRIPT"
198
- [ "$status" -eq 0 ]
199
- }
200
-
201
- # ── Shim PATH-resolution behaviour (ADR-049 contract) ──────────────────────
202
-
203
- @test "plugin-validate-ci-gate: invoking shim runs the canonical body" {
204
- write_plugin "alpha" '{"name":"alpha","version":"1.0.0","description":"t","maturity":{"schema_version":"2.0","band":"Experimental"}}'
205
-
206
- run "$SHIM"
207
- [ "$status" -eq 0 ]
208
- }