@windyroad/itil 0.38.0 → 0.39.0-preview.471

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.
@@ -484,5 +484,5 @@
484
484
  }
485
485
  },
486
486
  "name": "wr-itil",
487
- "version": "0.38.0"
487
+ "version": "0.39.0"
488
488
  }
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ # packages/itil/bin/wr-itil-plugin-validate-ci-gate
3
+ #
4
+ # ADR-049 shim — resolves the canonical body in this package's
5
+ # scripts/ dir. Canonical body at
6
+ # `packages/itil/scripts/plugin-validate-ci-gate.sh`; this shim is
7
+ # the `$PATH`-resolvable entrypoint that CI and adopter trees invoke.
8
+ #
9
+ # P263 — implements ADR-063 §Confirmation #11 manifest-validity gate.
10
+
11
+ exec "$(dirname "$0")/../scripts/plugin-validate-ci-gate.sh" "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/itil",
3
- "version": "0.38.0",
3
+ "version": "0.39.0-preview.471",
4
4
  "description": "ITIL-aligned IT service management for Claude Code (problem, and future incident/change skills)",
5
5
  "bin": {
6
6
  "windyroad-itil": "./bin/install.mjs"
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env bash
2
+ # packages/itil/scripts/plugin-validate-ci-gate.sh
3
+ #
4
+ # P263 / ADR-063 §Confirmation #11 — CI pre-publish manifest-validity
5
+ # gate. Loops every `packages/*/.claude-plugin/plugin.json` in CWD,
6
+ # runs `claude plugin validate <plugin_dir>` (NON-strict — see RCA
7
+ # note below), accumulates failures, and exits non-zero if ANY plugin
8
+ # manifest fails validation.
9
+ #
10
+ # WHY NON-STRICT (P263 / P258 refined RCA, 2026-05-30):
11
+ # - The historical P258 incident's failure class was a RECOGNISED
12
+ # top-level key (`hooks` / `skills` / `agents` / `commands`)
13
+ # carrying wrong-typed content — caught by `claude plugin validate`
14
+ # non-strict as a hard ERROR (`Validation errors: hooks: Invalid
15
+ # input`).
16
+ # - ADR-063 Amendment 2026-05-18's chosen safe-extension pattern
17
+ # places maturity records at top-level `maturity:` — an
18
+ # UNRECOGNISED top-level key — because unrecognised keys are
19
+ # warning-only and the plugin still loads. This is the durable
20
+ # design. `--strict` would promote `unknown field 'maturity'` to
21
+ # an error and REJECT every @windyroad/* plugin.
22
+ # - Non-strict therefore catches the historical incident's
23
+ # mechanism without rejecting the safe-extension pattern. The
24
+ # prose Confirmation #11 originally named `claude plugin install
25
+ # --dry-run`; P258 investigation refined to `claude plugin
26
+ # validate --strict`; this script's RCA refined further to
27
+ # non-strict.
28
+ #
29
+ # CLI VERSION PIN (set in `.github/workflows/ci.yml`):
30
+ # CI installs `@anthropic-ai/claude-code@2.1.150` before invoking
31
+ # this script. The exact pin protects against Anthropic-side CLI
32
+ # behaviour change silently breaking the gate. 2.1.150 is the
33
+ # version P263 iter 6 empirically tested against. Bump the pin
34
+ # only after re-running the iter-6 probe against the new version.
35
+ #
36
+ # LOOP CONTRACT:
37
+ # - Walks `packages/*/.claude-plugin/plugin.json` from CWD.
38
+ # - Does NOT short-circuit on first failure — every plugin is
39
+ # exercised so CI surfaces every defect at once.
40
+ # - `nullglob` makes a zero-plugin tree a no-op exit 0 (adopter-
41
+ # tree portability per ADR-049).
42
+ #
43
+ # References:
44
+ # ADR-063 — Amendment 2026-05-18 + §Confirmation #11
45
+ # ADR-049 — PATH-on-shim grammar (`wr-itil-plugin-validate-ci-gate`)
46
+ # ADR-052 — behavioural tests default (bats at
47
+ # `scripts/test/plugin-validate-ci-gate.bats`)
48
+ # ADR-014 — single-commit grain (script + shim + bats + CI + ADR
49
+ # amendment + changeset land together)
50
+ # P258 — root-cause driver (recognised vs unrecognised key
51
+ # distinction)
52
+ # P246 — sibling-class "gate-the-actual-load-bearing-surface"
53
+ # P263 — this implementation's ticket
54
+
55
+ set -e
56
+ shopt -s nullglob
57
+
58
+ fail=0
59
+ for manifest in packages/*/.claude-plugin/plugin.json; do
60
+ plugin_dir=$(dirname "$(dirname "$manifest")")
61
+ name=$(basename "$plugin_dir")
62
+ echo "--- $name ---"
63
+ if ! claude plugin validate "$plugin_dir"; then
64
+ echo "FAIL: $name plugin manifest validation"
65
+ fail=1
66
+ fi
67
+ done
68
+
69
+ [ "$fail" = "0" ] || exit 1
70
+ exit 0
@@ -0,0 +1,208 @@
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
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: wr-itil:transition-problems
3
- description: Batch-advance multiple problem tickets through the lifecycle in one invocation — Open → Known Error, Known Error → Verification Pending, Verification Pending → Closed. Loops the per-ticket /wr-itil:transition-problem mechanic (rename, Status edit, P057 re-stage, P063 external-root-cause detection, P062 README refresh) without paying N× SKILL.md reload latency or violating split-skill execution ownership. Produces ONE shared commit covering all surviving transitions per ADR-014 batch-grain. Use when closing the Verification Queue at the end of a `/wr-retrospective:run-retro` Step 4a pass, batch-closing release-aged verifyings during `/wr-itil:work-problems` AFK orchestration, or confirming multiple Step 9d verifications in `/wr-itil:manage-problem review`. Singular sibling: `/wr-itil:transition-problem` (one ticket per invocation).
3
+ description: "Batch-advance multiple problem tickets through the lifecycle in one invocation — Open → Known Error, Known Error → Verification Pending, Verification Pending → Closed. Loops the per-ticket /wr-itil:transition-problem mechanic (rename, Status edit, P057 re-stage, P063 external-root-cause detection, P062 README refresh) without paying N× SKILL.md reload latency or violating split-skill execution ownership. Produces ONE shared commit covering all surviving transitions per ADR-014 batch-grain. Use when closing the Verification Queue at the end of a `/wr-retrospective:run-retro` Step 4a pass, batch-closing release-aged verifyings during `/wr-itil:work-problems` AFK orchestration, or confirming multiple Step 9d verifications in `/wr-itil:manage-problem review`. Singular sibling `/wr-itil:transition-problem` (one ticket per invocation)."
4
4
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Skill, Agent
5
5
  ---
6
6